How to taxi with legacy code when the project was needed for yesterday

Hey. My name is Ivan Melnychuk, I am the Head of Development Department in a Ukrainian IT-company. In the publication I want to share personal professional approaches regarding the solution of the legacy code issue in the context of the rapid development of the project and talk about the techniques our team resorts to in cases of “when features need to be handed over“ for yesterday ”.

We deal with the project

In order to convey how accurate, thoughtful and painstaking, must be work with the Legacy, I will give an analogy with the house of cards.


This is what the outdated code looks like. If we decide to remove or replace at least one card from this building, we risk losing the entire house and leveling its remains with the ground.

Legacy behaves in approximately the same way. Therefore, the work of a programmer who has taken on the task of modernizing and “breathing a second life” into a project must be in some degree a jeweler. Most programmers try to avoid and generally “jump off the topic” of technical duty. Even compiled a hit parade of the most common quotes that had to be heard from programmers caught up in legacy conditions:

  1. We made a “simple” site, and now you want to get a new “bun”, and we need to rewrite all this, since we have a legacy ...
  2. No one knows how this works ..
  3. To add a module, you need to check the whole site - this is the only way we will understand what and where it can get out ...
  4. I will not go there in any case, everything is already bad there ...

But programming experience shows that life exists after legacy. After all, there is no problem in programming. There are only tasks that need to be addressed. And before drawing up an action plan “to overcome the hereditary code,” you need to understand how bad things are on the project as a whole. In the course of the practice, I identified 6 stages of the project problem:

  1. No technical documentation. The lowest threshold of problematic, as you can potestit and come to preliminary guesses about how it should work.
  2. No business documentation. If all documentation (both technical and business) is missing, the sensation “it seems, we have gotten involved in history” involuntarily comes. After all, even a business does not remember how this should work, which means that the team, at least, has no understanding as to the expected result.
  3. There is no one who designed it. If, in addition to the lack of documentation, there is also no developer who could explain how the project was supposed to work, then it already smells fried.
  4. We do not know what the user should end up with. It's one thing when questions arise only around the backend, but if we still have absolutely no idea what should be displayed on the front, then this is already close to the state of “the patient is more dead than alive”.
  5. 200+ usage of each function and they are called getA . The fifth level of difficulty: when you enter Legacy, you see function A and 200 usage, and no one knows why ...
  6. There are no programmers who would like / could develop. No comments.

Understand business

Business counts money. A business does not want to spend additional financial resources just on reworking what is already working. A business will never buy an idea: “I will do it in a new way because I don’t like it”. Therefore, always offer more.

Often, developers push business to useless ideas. On this occasion, there is a separate “fund of golden quotes”.

  • We are hiring a new team for high-quality code “cutting”. That is, we need a team of specialists who will do the project in parallel with the existing team. Not the fact that the result will be different, but the business should already contain two projects.
  • Stop adding features, now only refactoring! Officially, you declare to business: An absolute taboo on features, you can only bring order under the hood. Unofficially, you said: there will be no large-scale improvements and improvements to the project, only we will “fix” something locally.
  • I already have everything I need on WP, I just need to migrate the database. This is a “novice” symptom. Juna's favorite song: this is such a simple site, works for just an hour or two ...

It is necessary to negotiate with the business regarding the reincarnation of the outdated code, which is served by the sauce of new profitable features, from the position of opening new business horizons. However, before the negotiations you need to answer the following questions:

  1. Is business ready to grow? It is necessary to understand: does the business have a request for raising the financial bar or is it just necessary that the service work more competently.
  2. Stage prototype? Often, a business orders a simple prototype with which it wants to “probe” the market at the time the product is relevant. And only if he starts to make money, the business is ready to develop the feature into a more perfect and complete project.
  3. Development completed and now only support? It is important to understand the whole range of tasks.
  4. Is there enough fire in our eyes and will it not go out? The project should inspire, not demotivate. It is very important that your team wants to engage in the reincarnation of Legacy, otherwise people will gradually run to projects that are more interesting for them.
  5. Is there an architect? This is the most important question - do you have a person who can do the right architecture and start writing already good code? There is no point even trying to start if there is no architect. Otherwise, in a week you will become the one who created the problem legacy.

When you sell ideas to business, focus on the messages “new, create, add” ... The business responds perfectly to the proposals from the series: “We will make you a new feature and at the same time project X will be faster ...” and “To increase the conversion, we will add a new ... "

P - Planning

For quick and effective work with technical debt, you need a plan.

1. Definition of tasks on which we will parasitize. Why parasitize? It often happens: we sold a feature, and by it we partially mean refactoring.

2. Determining high level requirements. It is necessary to prescribe a clear business request for a “high bar” in order to compile the correct documentation.

3. Definition of the main modules of the system, the imposition of modules. Before starting refactoring, you need to understand the main modules of the system: where, how, what and with what can interact and differentiate the code into sections.

4. Definition of integration.When creating a specific module, we must think in advance about the possibility of building it into the next legacy.

5. Definition of the team. One in the field of refactoring is not a warrior. A team is a very important element of a successful outcome. The enthusiasm, team drive and excellent interaction between the participants of the must have process.

6. How are we going to test? If you are going to take a quality project, then you need to think in advance and options for testing the product.

Along with the above, it is also important to determine what the desired end result should be, draw up a scaling plan and prescribe the bottlenecks of the project. For example, in the case of code scaling, it is important to understand where problems could potentially arise in highload conditions (this could be a database, or heavy queries, or a grid, or some other intermediate link that could “fall”).

It is equally important to determine the boundaries of the project, where the old code was and where the new masterpiece will be. You should also consider approaches on microservices, or DDD, or maybe some other “nanomage” will be needed.

Ninja Legacy Techniques

After the “preparatory work” we approach technicians who facilitate the process of saving technical debt. There is no universal recipe and panacea for all ills, but as you work on highload projects you have compiled a list of ingredients with which you can make a really “tasty” code.

1. Do not reinvent the wheel. For me, this is the main code hacking hack. Everything is already thought up to you, you should not resort to dancing with tambourines and other experiments to solve problems with the legacy code.

2. Code standard. Without a single standard, each developer will write in his own way. “Author's style” will contribute to chaos and increase code-trash even more.

3. Code review.There is only one presence of the code standard. It is also necessary that the team be responsible for checking it. Otherwise, everything will return to normal, that is, to the level of the old code.

4. Static Code analyzers, PHP mess detector detector etc (instead of thousands of books) . These and other automatic types of technology will be needed to speed up the process, in particular with the same review code.

5. We try microservices. Separately, there may also be modules or libraries. Why microservices? Their advantage is to maximize the isolation of logic and limit it to a specific API. The advantage of the latter is that the API is a more monolithic entity compared to the “adapter in the code that can be fixed”. However, the API has one drawback in the form of additional costs for the network.

6. Database architecture, data sources. That database is considered the first “bottleneck” of any Legacy. But everyone designs as he wants, and even in SQL you can find non-flawed flaws. Here are some tips for working with the new database:

  • Screw nothing, thirst all. If you want to change the old incorrect data structure to a new data format, faster and more productive, you can go two ways. The first is to put a new base, completely removing the old one, and come what may. The second - in the case of a hard legacy in parallel to introduce a new format. Figuratively speaking, plant a new one near the old tree. Why is the second way justified and more promising? Because everything new will work efficiently, and if problems arise during the deployment or at the integration stage, you can simply roll back the code, without the need to roll back all complex database migrations.
  • A new database is created in the correct structure. When creating a new resource, it is important to control the places where we are writing a new structure. In parallel, you need to create support for the old structure, since it is inappropriate to get rid of it completely. That is, we continue to write new material, and at the same time we support the old template, in which we transmit everything new, and thus we allow the old to work too - as if in the old way, but supporting the new structure.
  • We control the whole record. Do not miss the details of the field of attention, in order to guarantee the support of the database.

7. No SQL? If from an architectural point of view you can operate on entities, operate on them. The concept of something definite and finite will help you not to create unnecessary, duplicating relaying.

8. Decorators, adapters, mediators ... These patterns are one of the main ones for integrating the new code into the old Legacy.

9. Plan B, or rollback plan for integration. Many make the mistake of forgetting about it. It is vital in the situation “when something goes wrong” when pouring new material. That is, as soon as we begin to build architecture, already at this stage we must understand how we will roll it back in the event of a bug.

10. New code without (docks) tests after a week becomes legacy. No matter how beautiful your code is, without documentation in a week it will be in the status of “legacy” - because of its incomprehensibility.

11. Testing.If unit tests are not affordable, then we use Smoke, functional and integration tests. How realistic is it to sell unit tests to businesses under the dressing “to do the job beautifully?”. In our reality, this is more rare than regularity. If for some reason it does not add up to “units”, then we turn to Smoke, functional or integration tests, and also do not forget that we can delegate a task, for example, to a manual tester.

Instead of an epilogue

The most important thing in this story is to do the work and not leave behind legacy Legacy and 6 problem stages (listed in order from simple to more complex):

  • No technical documentation
  • No business documentation
  • There is no one who developed it.
  • We do not know what the user should receive.
  • 200 + usage of each function and they are called getA ()
  • There is no one who would like / could develop it.

Also popular now: