Subjectively: refactoring is a juvenile "disease." According to personal observations, somewhere after 26 years old begins to let go. As in that old phrase: "Who in his youth was not a revolutionary - he does not have a heart, who in maturity did not become conservative - he does not have a mind". Therefore, until I finally let go, I will try to describe refactoring use cases and possible goals that can be achieved with its help.
Inspirers
I started writing after a regular review of the pull request for 150+ files, where the new functionality and refactoring of the existing one were seriously mixed up. Refactoring was not only cosmetic, but also logical, which caused the most pain. For example, in Ruby, the amount == 0
boldly replaced with amount.zero?
without taking into account the fact that for the case of nil
in the amount
these constructions are not equivalent. All this was explained approximately as follows: "but according to the code the standard is supposed to be so!" The logical question is "what is the purpose of following the code to the standard and in general, what is your goal as a developer?" the man closed in on himself and slightly guiltily repeated "but according to the code standard, it is necessary to write like this ..." and looked like a blonde in a clothing store who could not cope with the desire to refactor buy everything.
Definition
The topic is delicate, so you need to pay special attention to the question "who is who?" So, according to the wiki , refactoring is a process of changing the internal structure of a program that does not affect its external behavior and is designed to make it easier to understand its work.
For my part, I want to narrow the boundaries and define refactoring (in the worst sense, these words) as any changes that are not directly related to the task being solved and do not change the external behavior of the system, but are performed within the framework of the original task.
That is, I want to talk not about the planned change of the code base, for which the work area is outlined and specific goals set, but about spontaneous modifications that occur during development.
Product value
Now I start from afar. Source code is not a goal or a value. Of course, aesthetically or artistically, it may be of some interest, but these are exceptions. In general, the code is a tool for creating a software product that someone uses. Therefore, for a start, it would be good to determine what values are in the product.
Direct product values
It's simple. The product is used, so direct values are what the user clearly feels / sees / feels. Namely:
- all sorts of product functionality;
- usability (UI / UX, speed, fault tolerance, etc.).
The second point may cause some discussion. After all, many believe that this is not important. Since if the functionality is good, then it doesn't matter what it is wrapped up. Good examples of functionality without imputed UI / UX: Redmine and SAP . However, I disagree with such a view and closer in my views to Comrade Alan Cooper and his "Mental hospital in the hands of patients."
Indirect Product Values
These are the values that in themselves do not affect the user. But they can "shoot" or "accumulate" and have an impact (of varying severity) on the product or its functionality.
- Bugs. The borderline case of values. They are secondary because the values themselves do not carry, but take it away from the neighboring features.
- Purity. This is about readability, modularity, minimization of incoming components, standardization and unification of interfaces, and so on.
- Documented. This is about the code and explanations for developers, not about the business description or user yuzkeysy. It is well illustrated by the phrase of a cheerful man from one of the interviews: "The logic in the database is written as a book."
- Scalability / security / security. The user does not see them until something bad happens.
Developer Values
A very important category that many lose sight of, but which always affects the result.
- Code by standard.
- Indentations on feng shui.
- Other deals with conscience. After all, the code was written, which means there is a result for the day, and therefore there is a benefit.
- Consent code with the inner world.
But let's be honest. All this is not about the values associated with the product and the end user. This is about psychology and personal cockroaches.
View from the business
For the sake of completeness, one should look at all this from the business side, and not from the software product. In this case, the division into direct and indirect values becomes quite banal: direct - obviously bring money and you can give an unambiguous quantitative assessment; indirect - money is not brought and / or a quantitative assessment is very difficult to give; values for the developer of money do not bring in any form (perhaps even take them away).
For example.
- New feature with screwing OAuth increased the number of registrations by 10% and we got + 1k $.
- They divided the billing module into several independent parts, based on the single-responsibility pattern. It seems that it became easier to maintain, but it did not work out in any way.
- We brought the code base to conformity with the code standard and ... did not receive "anything".
It is worth noting that, from the above-mentioned assessments, the feet of a business favorite speeding up, general hurry and unwillingness to devote time to anything other than functionality and, perhaps, bug fixes grow. After all, direct values can be estimated and “sold”, and indirect values can be very difficult, or impossible. And it turns out that indirect values are realized either by virtue of the engineering background, or are understood on an intuitive level, or are thrown away as "useless."
In fairness, here we need to remember the concept of enabler, which "opens the way" to the implementation of the desired feature, but does not carry an explicit profit to the user. But that's another story.
And here refactoring?
At a minimum, despite the fact that it can only affect the indirect values of the product. Therefore, the user will not get better from any refactoring.
It is also important to remember about entropy. Refactoring always minimizes it. To reduce entropy, ideally, we need a team of architects who minimize entropy at the design stage. I will quote a piece from the Mythical Man of the Month:
System programming is a process that reduces entropy, and therefore metastability is inherent in it. The maintenance of programs is a process that increases the entropy, and even the most skilful conduct of it only postpones the confluence of the system to hopeless obsolescence.
Therefore, if we consider refactoring as part of the program maintenance process, then the less refactoring, the longer the code will live without rewriting.
What goals can a refactoring have?
Let me remind you that I am talking about a spontaneous change during the implementation of the features, and not about the planned changes. In this case, the definition of the goal lies entirely on the shoulders of the developer. He should ask himself the main question "why?", Answer it and after that, move towards the intended goal.
For entropy!
This is the most difficult to crank. And to push through the review is unrealistic in general. The goal is certainly good: to clear the springboard for new achievements, as well as to clean up slags and toxins accumulated during the time of product support. But shoveling a couple of modules from scratch without losing anything along the way is not an easy task. It should be solved together with business analysts and architects, if any. So there are so few who risk volunteering.
For the documentation!
It is already easier. Rename variables / functions according to the “what's on the box and the box” principle, simplify the constructions due to the capabilities of the language and libraries, add comments in non-obvious places, etc. This can be done alone and, with the right approach, you can do well for yourself as well as for your future colleagues as well as your neighbors.
For speed!
To be honest, such work should be allocated to a separate task. Since either you are satisfied with the current capabilities of the system and you don’t need to do anything, or you know what exactly and how much needs to be accelerated.
Everything is included in this category: from the innocuous correction of N + 1 to serious acceleration due to changes in the algorithms of work. The problem is that the parity of bugs always sits at the speed. Here, to the case, is an example from the life: inside one transaction, the data in the database is pushed and in the same transaction the task is put in Sidekiq; Sidekiq's queue on Redis and the transaction does not apply to it; with an increase in the speed of the queue, the task is sometimes taken for execution before the data commits; You can imagine the consequences and the debag process yourself.
For refactoring!
Imagine that you used an apartment cleaning service. They came, started cleaning, but along the way, all the furniture in the apartment was rearranged and the curtains were shifted from the living room to the bath with the argument “in such conditions the cleaner was more pleasant to do her job.” Picture with "WTF ?!" you can guess yourself.
I hope you understand that you need to think not about yourself, but about who you are doing this for.
Humility and acceptance
In the end, be sure to give a "manual" about what to do before refactoring. True, this is not a TODO-list, but rather a list of facts with which you need to accept and either accept or not take action.
- I increase the number of bugs in the project and I can get a tambourine for it.
- I become the owner of the refactored code and all questions on it, first of all, will be sent to me.
- By my actions, I do not produce anything of value to the end user.
A little bit of explanation.
- Any code change has a non-zero chance to generate a bug. And since this action is not related to the ultimate functionality, then you simply spawn bugs without generating core values. It is good to be aware of this and not to pretend to be hoses when they come to you with questions.
- Excuses like "anotate previous" and the like are very poor, because there is no such feature in the same github / gitlab. Plus, the previous author confirmed that it is in his configuration that everything works, and he is not responsible for your changes and loses some of the picture of what is happening. More precisely, you take it from him along with responsibility.
- The user really doesn't care about refactoring, he is interested in stability and functionality, and refactoring is not about that.
And once again: if you do not agree with at least one of the points - do not start refactoring. Better read Habr, Lurk, drink tea or, at worst, gash the following feature with dashboard.
the end
Do not judge strictly. If possible, criticize constructively. And always think about the purpose of your actions. Thank.