“Plumbing Syndrome”: rules for working with legacy code in testing
Many people came across a newcomer who came to the project and declared that “everything must be urgently redone”. And some themselves said it or thought. This is the “plumbing syndrome”: behavior characterized by the desire to do everything in its own way, “right” when working on a new project or when switching to a new job. So, the existing code, technology or tools need to be rewritten, preferably “for themselves”. The topic would be commonplace if it were not repeated so often from project to project, with each new recruitment of staff.
The longer the project “lives”, the more the “historical” inherited code accumulates in it, and the higher are the chances of meeting the burning eyes of the affected “plumber syndrome”. In this post I want to tell you what principles Parallels adhere to (at once the spoiler is the principle of “do no harm”), and how we act if it is decided to “redo everything”. Although, in general, we believe that this syndrome should be treated, and that the use of Legacy is sometimes even useful, as it allows you to release the product on time and not waste time on developing your technologies.
When you work with long-lived programs, a fairly large percentage of them are occupied by the legacy code. For example, Parallels Desktop has been developed for over 15 years. Every year the team expands, new people come, look at what is written and declare: “Everything is crooked, let's tear off the hands of the programmer and rewrite everything”. Common situation?
Before we begin to say whether the Legacy code is good or bad, I would like to decide on the concepts of who understands this by what. Two definitions are commonly used: the first is code that is not covered by tests. From the point of view of automatic testing, all code is not covered by tests. Second, the Legacy code is the code that you inherited. When you need to understand how it works, but no one to ask. And you have to tinker with it yourself.
I. The best is the enemy of the good. If the inherited code or the system performs all the necessary functionality with an acceptable quality, then there is no need to improve it, it is better to direct your boiling energy to something more useful.
Ii. From important and new choose important, from equal choose new. If the legacy code contains important functionality and is not covered by tests, it is necessary to pay maximum attention to it, both in terms of processing the code and in covering it with tests. If legacy code and new features are equal in importance, then you should focus on new features (development and tests).
Iii.If the old can not be improved, build a new one next, then throw away the old. If the inherited code is necessary, but it is impossible to change, use the old code until you write and debug a new one. When the new code will work, the old can be discarded.
What to do?
Step 1. Look at who said
1. Freelancer . Most often, people who have no experience of joining a large project from the outside rush to completely redo the code. For example, I myself first worked on freelance, wrote projects from scratch, and I, like many similar developers, have developed a fairly stable habit - to do exactly as I see fit.
2. Inexperienced. Sometimes such statements indicate a lack of qualifications of the person himself in the subject area: he does not know the history of the project, and, for example, the fact that this “terrible” (in his opinion) construction resulted from the fact that during the development process, people came across external bugs systems and began to bypass them. As a result, there was such a spaghetti from interconnected patches and crutches to these bugs. Such knowledge of all existing pitfalls in a person from the outside cannot be in principle.
3. D'Artagnan. Most often this happens with engineers who do not have product experience and experience in large projects who do not understand what price they get. A person beats the heel into the chest, and says that he will do brilliantly, fresh, and in just a week, but he may be deeply mistaken about his abilities, and because he completely misses such moments as testing and embedding into the existing larger system.
4. High quality specialist.The only type of “applicants” that you should listen to, although you still don’t rush to rework on his advice, is not yet implemented. Step 2. It is possible that we got an ultra-class professional, and he can really prove that we don’t so, and can do better. But the fact is that I have not met a single senior level person with such statements. When a person grows to such a level, he can already imagine the project as a whole and understand all the shortcomings of the “revolutionary” method.
Step 2. Making the argument
First of all, a person needs to stop and analyze his arguments. To initiate this trial should be a team lead. With the proviso that the "plumber syndrome" did not begin to suffer the man himself who came to the team lead. Then the analysis of the flight is the business of the project manager, although, frankly speaking, a mature team lead never initiates a complete rework without serious argument.
What arguments will not pass:
"We will write our own, with chess and poetess"
Most often, if a product has been on the market for a long time, then it already works somehow. He has already shown that, despite all the terribleness of what is under the hood, it is functioning. For example, we have Parallels Desktop (a solution for running Windows and other operating systems on a Mac without rebooting), and sometimes you can hear from newbies: “somehow you have everything too complicated, let me write my virtual machine”. And since such things are in principle impossible to do without a swoop, when a person says this, he is either not in the subject or not in himself. It is necessary to give him first to gain experience in the project and understand why this was how it was originally implemented.
"It's not beautiful"
The trouble is that often a person has no other arguments. “Not technological,” “made on some old stuff,” “why it’s written in C, it’s now fashionable to write on Go”. These are not arguments for reworking the system. Because when you go beyond your one piece of code, you begin to understand that your reworking may be worse than what it was before. It can look more beautiful inside and work slower, which is unacceptable for the product. In Parallels, I did not see this, but in the previous company we had to fully experience all the consequences of such a step. We decided that the family of drivers for certain equipment was ugly implemented, and we need a more elegant and advanced design, which will be easier to maintain and add new functions to it. The new and beautiful wrote a year and a half, but in the end it turned out just as awful and did not give any advantages.
Why a multi-year code of a large project is better not to touch
You can even kill your project.
Where is the guarantee that you will write something again and will it work correctly? After all, this is not yet. From a business point of view, you need to live today and ensure the continuity of income.
Crutches can be broken.
In any project there is such a thing as kludge (better known as a “crutch”), and a lot of undocumented things. Yes, there is such a development methodology, when the documentation is written first, and then it is developed strictly according to it, but it still showed itself in the 90s as too inertial for business tasks. Maybe this way you can make a rocket, that is, in processes where development takes several decades, this is justified, since there are big risks of deviations. And even there you have to make some changes on the go.
And from the point of view of commercial development of software, there is not so much time to first take everything into account in the documentation, and then do it. And it turns out that all products have a large amount of unsaid data. We met with some kind of environmental problem, for example, some kind of iron worked around the specification, made a workaround for it. In many cases, if it was a relatively minor change, then it is often forgotten and is not reflected in the documentation. It's just that it is inserted into the code and, more often, with some little sane comment, unfortunately.
And it begins: let us throw up all these crutches, since it is unclear what spoils the code. And do not think where it will lead. For example, when we were doing one of our patches for the Linux kernel, we had such a crutch in one place: it was very ugly and, at the same time, rather poorly described. And then we learned in the discussion: certain equipment without this kludge does not work. Yes, it is no longer available, but users still have it and it works. And the loss of support for this hardware is contrary to the philosophy of the Linux community. We had to rewrite our code in such a way that this workspace would remain one-to-one, and after that everyone would be satisfied.
You can waste resources
An example of such a waste of resources is given above. It should be understood that any revolution leads to civil war, to a certain period with a deterioration in the state of affairs in which nothing will work.
You can lose the initiator and the project
“Plumbing Syndrome” affects mainly new employees. It is worth remembering that such people are at risk, because they can leave the company for a trial period (no wonder they say that the trial period is not only for a person, but also for a company). The man was given a carte blanche, he began to redo it, and then said that he did not like coffee in the company and left. This is a very dangerous situation. It turns out that there is nothing new, and the old have already broken. Then someone (and not at all an enthusiast) will have to bring this into a working look.
What to do when the decision not to alter is obvious, but the person “burns with an idea”?
To give time to cool down and think.
You just need to give time to a person who has come to a large existing project for a closer look. For when an idea comes from a person who has been working in the company for a long time and specifically with this product, then his initiatives will be taken much more seriously and his arguments will be analyzed. You need to explain to him that you should not throw in an area with which you are not familiar enough and do not know the current situation. It is doubtful that a person who has just come in, having looked at the code, will be able to reasonably explain why everything is wrong and why it needs to be changed.
If such a refusal or proposal is very demotivating for a person, then it is a reason to make a note that perhaps this developer is not ready to work in a team and there may be further difficulties in communicating with him (and this is a very important factor for us). Since then the team-leader will have to work separately, in the “manual mode”. Perhaps such a person should reconsider their views on a career and go into freelancing, where you can create everything “as needed”.
Direct his energy in a different direction.
Most large products always have some bottlenecks and problems that regularly arise, since everything changes outside. Although a new person, in my opinion, is still very dangerous to let in to the code, until he works out debugging minor bugs for a couple of months, does not become familiar with the existing code, and does not prove his level of qualification.
You can give him a task from some side projects so that he can write down his new one there and see what happens. This is under the condition that there are such slots in the resources, as there are also a limited number of survey tasks, here as with a venture business - in 100 companies invested, with one received a return.
When it’s still necessary to redo
The product dies under existing conditions.
Argument for rework - if the external environment has changed so much that the existing product has stopped working. For example, when a new operating system was released, to which users began to migrate en masse, but something was changed in this OS so that your product, which under previous versions worked fine, stopped functioning or the user became completely uncomfortable using it. Or when the platform dies off - as an example of the old BeOS can be cited, under which a lot of work with multimedia products, for example, composed music. The system died, and since it was quite distinctive, the codes from it were practically not transferred to other systems. From OS BeOS itself, the same thing happened: there were Atom computers that they were guided by, and then the manufacturer stopped producing these processors, and the people who wrote under this computer, actually remained at the broken trough. And they had to urgently adapt for Intel, which turned out badly - the niche was occupied and another OS reigned there. And in order to somehow extend their life, they had to seriously redo in the direction of improving portability, and so on.
Plumbing Syndrome worked: rework stages
It is necessary to do evolutionarily and in parallel, without breaking the system. The process and stages of alteration depend on whether we change the whole product or some essential part of it. If the whole product, then this is actually the beginning of a new project from scratch. But in most cases, they still change part, since in the first case more than one year will pass before the new code base attains stability and consistency with consumer qualities in order to satisfy at least the level it was.
If you replace the component, then it is desirable to do this: if the external interface does not require a change, then we calmly make the second implementation. It is advisable to immediately find the dividing lines: here the old remains, but here you can redo it, find the entry points. And so, preserving the interface, change the stuffing.
It’s like a car with a gasoline engine decided to replace it with an electric motor. For the user, little has changed: there was the same body, four wheels and a steering wheel. And under the hood may be all else.
If you can find such a partition point, then you can evolutionarily alter and those who stand at that partition point may not even notice the changes (except, hopefully, improving the quality of work). And then in the process of internal testing, switch and save the product. Unfortunately, this is not always possible, and then reworking can lead to a catastrophe.
Or this option: the interface is fixed, the implementation is done, and then the interface begins to change iteratively.
It makes sense to start a serious rework on the side branches and until it gets a finished look, it does not integrate into the main product. Even with respect to subsystems, it’s worse if under this name we started doing something completely new and the team broke up, then there is no product at all.
Instead of conclusion
One boy was born with a nut instead of a navel. And he periodically asked his parents why he had a nut there. Parents promised to tell him about it on the 14th anniversary. The boy turned 14. And here he again approached his father and mother and asked why he had a nut instead of a navel. Parents promised to tell him about it when he was 18 years old. At 18, he asked again and then he was told that there is a tropical island on which a palm tree grows, and a chest is buried under this palm tree. There are answers to all his questions. The guy saved money for a long time and still poisoned on this island. Found a palm tree, dug up a chest in which lay a wrench. Without hesitation, he unscrewed the nut with the found key and his ass fell off. Moral: sometimes you just should not look for adventures on the fifth point.