📜 ⬆️ ⬇️

Refactoring syndrome

image
There is an opinion that software systems, being an object that is not entirely material, are not amenable to aging. And if we talk about physical aging, then indeed, the chances that the letter “o” in the class name suddenly shrivels from old age and turns into the letter “c” - really small. But instead of physical aging, software systems age morally. Over time, a load of errors accumulates due to inaccuracies in the initial requirements, lack of understanding of the requirements by the customer, architectural errors or unsuccessful compromise solutions; and even smaller errors, such as poorly understood code, its high connectivity, the lack of unit tests and comments, do their dirty work. All this leads to the accumulation of technical debt (which was discussed last time), because of which, when adding a new opportunity to the system, you have to pay “interest” in the form of higher realization costs and lower quality of the result.


There are several ways to pay technical debt, and the simplest of them is to refactor a system or some of its parts, select new abstractions, write unit tests, comments, or completely rewrite some pieces of the system. However, as in any other business that a glorious programming soul is engaged in, this soul often overturns the stick and instead of a pragmatic approach to improving some parts of the system to get a reasonable benefit in the future, it throws everything back and forth with a checker: what is needed It is not necessary and that it is not worth rewriting at all.

All this leads to another metaphor that just describes a similar unremovable desire for rewriting the old code - the refactoring syndrome.
')

Symptom 1. Someone else's code - g # $ but



As soon as more than one developer appears in the team, problems immediately begin: different people may have different opinions about the formatting of the code used by idioms, the programming language, and the approach to solving applied problems. In addition, no matter how understandable the requirements, no matter how expressive the programming language, no matter how good the code and no matter how well documented (although all these combinations are never found in one place), many thoughts and intentions of the developer still remain only in his head. And, not understanding his intentions, we very often arrogantly believe that the current decision is wrong and the same can be done differently and significantly better.

And realizing that the whole world has gone mad, many representatives of our “race” rush to the barricades and begin to rewrite or refactor someone else's code, simply because it is a stranger. The classic syndrome “this is not invented here” (Not Invented Here) manifests itself, and all any code written not with your own hands is not understandable automatically (for many letters) and, therefore, bad.

Such a disrespectful attitude to someone else's code, firstly does not color the developer, and secondly, in most cases does not reduce the technical debt, which should be reduced due to this refactoring. The system as a whole does not become more followed and understood, it is just now closer and clearer to one specific person. Of course, for some time the system maintainability improves, while the author of these changes is engaged in new features, but all the benefits will end exactly when another developer takes on this piece of code. And the process begins again.

Symptom 2. The desire for the ideal code



The pursuit of the ideal code is the most good intention when changing the existing code, although we all know where such intentions lead to. Blind adherence to ill-conceived coding standards is not much better than the lack of coding standards at all. The beauty of the code is not an end in itself; the code can be beautifully designed, all functions can be small in size with a sufficient number of comments, and even covered with unit tests. But this does not mean that this code will cope with its main task, since, corny, no one bothered to find out this task from the user.

For an ideal result, an endless amount of effort is required. The code should be quite beautiful, clear enough, with a sufficient number of comments and unit tests. From a unit test that covers completely trivial cases, or which is so incomprehensible that it is almost impossible to accompany him, more harm than good is more likely. Unit tests are an invaluable source of information about system specifications, each of them must tell a story about one of the ways to use this class or part of the system. They should not be many, and they should not be small; they should be just enough so that the costs of their writing and accompaniment are justified (*).

Symptoms 3. “I fight because I fight”



Over time, from the height of their own new professional experience, thanks to a clearer understanding of user requirements and an understanding of their own system, even their code begins to look awful. How many times have you caught yourself thinking: “Well, damn, who wrote this nonsense?” And then with surprise found out that this someone is you.

This is a normal situation, because small debts accumulate at all. Moreover, the reverse situation, when after a while you cannot find problems in your own code, it seems more suspicious. Therefore, improving your own code is a process just as useful as improving someone else’s code. But there are cases when your own code undergoes significant alterations of the heels once a year, but at the same time new features are added all the same slowly, and if you look at this code from the side, nothing in it really changes.

In fact, this is some kind of the previous syndrome, but when the driving force is not an ideal code, but one clear, ideal solution for it. It is normal if a person does it for his own project, when new solutions of already well-known tasks are acquired, but it is not quite reasonable when it is done for a commercial product. After all, it turns out that the code is rewritten just like that; just because today I learned about a new feature in my favorite programming language or about a new library that solves this problem much better. But after a while, all new features come out (or you learn about them) and the process is repeated again from the beginning, but no debts are paid and nothing valuable is added to the system.

Symptom 4 ... 1001



I think that every fairly experienced developer has come across all these symptoms and, probably, not one dozen others. I didn’t set myself the goal of describing all possible reasons that might lead to unnecessary rewriting of the code. The essence of this little note is that code, like architecture, is not an end in itself; All these are just tools for solving specific tasks of business users or any other tasks that should be solved by an application or library. The code and architecture should be good and flexible just as much as is necessary for successfully solving these tasks in a reasonable time frame now and for reasonable labor costs for solving new problems in the future.

In almost any case, pragmatism and the absence of extremes is the best choice and refactoring of the existing code is no exception. Do not forget about the Pareto law (80/20 principle): twenty percent of the effort to improve your code and maintain it in adequate condition is often enough to improve it by 80%. And if this is not the case, then the patient may be more likely dead than alive, and investing additional funds to cover such a large technical debt simply makes no sense and should we start from scratch?

-

(*) Exceptionally just in case, I will say that I consider unit tests to be the most valuable tool in the developer’s arsenal. This is an invaluable source of information about how the system should work and an amazing litmus test of design quality: if the code cannot be covered with unit tests, then something is wrong with it. This does not mean that I cover all my code with tests, but I will definitely “try on” them to my classes and change the design if it is impossible to write them or it is very difficult. But at the same time I treat the tests with sufficient pragmatism and try to ensure that their number is the most optimal from the point of view of labor costs to the benefit obtained from them.

Source: https://habr.com/ru/post/120000/


All Articles