Zen and the art of clean code support
Talking about clean code is endless, but the next article by Dave Nicoletta is very metaphorical and, we hope, really worthy of translation. Let it be a bit “edifying”, as the author pre-informs the readers in the original article.
Over our years, a bad habit has been established. Having used any tool, we now and then forgot to put it in its place. The next time he needed someone, he had to spend more time searching for a tool than to solve a problem that had arisen. The saddest thing is that even the one who took the instrument last and threw it at random was doomed to exactly the same quest. It often turned out that it was faster to buy a new inventory than to look for the tool that we have - we know for sure! - somewhere lying around.
So we have accumulated four medium Philips cross screwdrivers, three with a flat slot, a bunch of extra tongs and wrenches, sets of adapters. I'm not talking about an impressive collection of pens, rolls of scotch, batteries and other good stuff scattered everywhere.
Once we decided: enough is enough! They have allocated their place for all things and put things in order with our inventory. Stock tools handed over to charity. We made every effort to cultivate self-discipline and always put the tools only in their place after we work with them. The quality and volume of work per unit of time went up sharply. Stress, wasted money and spoiled mood has become much less.
Restore order in the corporate garage
What if auto mechanics working in a corporate garage would throw tools anywhere? They would spend more time searching for tools than actually working. Parts would be put in the wrong place, lost, rusted, spoiled, they would just be stolen. The cost of supply would greatly increase.
It would take more time to complete tasks, but the quality of work would decrease. When a mechanic has to work with rusty, worn and broken tools, it is difficult for him to properly adjust and fix the parts. In addition, the habit of organizing a mess in the workshop will inevitably affect the quality of work.
Customers will be fed up with endless carry-overs. Soon they will go to more reliable workshops. Somehow do without you. Perhaps, the analogies with software development and support are already obvious.
Restore order in software development
Let's look at a specific example: incremental refactoring.
This expression baffles many. I don’t know what kind of word baffles them: “incremental” or “refactoring.”
Incremental (gradual) refactoring is fundamentally different from large scale. It seems to many that any refactoring is necessarily “large-scale”, that it must be “sanctioned” by someone, and therefore the work must be delayed. In fact, if you neglect the refactoring in the course of work, then everything is significantly delayed.
Most technical coaches, including myself, hardly explain the difference in this case; not because this difference is by definition difficult, but because it is really hard to formulate in words. However, I think that the habit of carefully considering the available inventory and keeping track of supplies is a good analogy in this case.
Gradual refactoring is the same as maintaining order on a workbench even in the midst of work. Use a screwdriver - put it in place. We are not going to rebuild a workshop for this for every new task. The bottom line is, rather, the ability to finish ... how to finish what you started. Strip the ends.
A gradual refactoring does not take much time and does not require someone's permission from above. If it comes to that, you need to ask permission not to clean up after yourself in the code, if you need to hurry. The ability to keep the code clean all the time should in fact be considered the basic professional skill of the programmer. It's a shame that today the “clean code” needs propaganda, and some programmers even resist targeting such purity. Gradual refactoring has nothing at all with large-scale architectural refactoring, which really needs to be carefully planned, set aside time, money and people.
In programming, there is a so-called “scout rule”: keep the code at least as clean as it was adopted. The same applies to the storage of working tools at home. If we are looking for pliers, but notice that the slotted screwdriver accidentally got to the cross, and the cross-head to the slotted screwdriver, we put them in their places along the way. We do not need official approval to do this.
This is how gradual refactoring works. Before us is a code fragment, and we need to add a new condition to the list of available constructions. Note that the list is implemented as a large if / else block. We decide that it needs to be redesigned as a switch or select statement, while at the same time adding a condition. One could argue: is it much better than an if / else block? Yes, you are right: not much. But a little better. When someone next reads this code after you, he can even better refine it, since you have improved the initial position for him. If you have ever done something similar before, then you probably noticed that by just carefully reading all the conditions, you sometimes found duplicate constructions, then a non-optimal order of expressions; you may have come across some condition that can never be met, or even a logical “hole” through which the entire control sequence will fail through the if / else block, and some case will not be processed at all. Just be glad you found it now, and not late at night, when the corresponding ticket from the technical support service arrives. At such a moment, when the eyes stick together, there is absolutely no desire to understand the confusing code.
Maybe we will add some new functionality to the application and note that the function / method we have written is very similar to another (other) that we already have in the code base. Having spent only a few seconds, we will get rid of such duplication, even without additional tools, which are offered to our services in smart IDE. You can refactor without doubting, since we have accustomed ourselves to self-discipline and guarantee that we have already written micro tests (unit tests) covering this case. Then manual refactoring is not terrible. In the end, come up with at least one reason, why not do this?
“Long-term” is usually not as long as it seems.
I often hear from different people that refactoring brings "long-term" benefits. Although, in theory, it is, here, in the Real World, we constantly have to hand over work within tight deadlines. However, if we talk about maintaining the purity of the code by small gradual refactoring, the “long-term” lasts exactly until the moment when someone else touches the code base. Exactly until next time.
The bad news is that the opposite is true. If you do not erase the code in the course of work, then it quickly deteriorates. We do not have a ten-year “airbag” that would allow us to accumulate a marriage with impunity until the problems start. The next change that needs to be made will take away a prohibitively long amount of time, the risk of code regression will increase, and the situation without proper attention to it will only get worse.
If we are making a mess only to satisfy the customer’s desire (and he wants the finished product quickly), how are we going to continue to meet these requests, after we make sure that no quick changes are made anymore, since we brought the code to mess and support it is impossible?
What is fast, what is slow?
Customers will always want you to work more alive, no matter how fast the delivery you arrange. The most effective way to reduce the time to release is to do everything right; to do well; constantly clean the ends, always, without exception. Cutting corners in order to “speed up”, in practice we only slow down, and not in the ephemeral “long term”, but here and now.
When a customer requires you to work faster, it does not mean that he allows you to work carelessly. Naturally, it seems obvious to him that he shouldn’t remind us again and again with each request that he is interested in high quality. High quality is implied as one of the components of our work.
We, as engineers, choose for ourselves whether to consider gradual refactoring as a basic element of our professional activity. We do not ask if we can work properly, just as the surgeon does not ask the accountant if he has time to wash his hands before the operation. The time spent on the operation is exactly as much time as is necessary for the operation to be successful. The patient needs to gently remove his appendix, and, after being discharged, the person can return to normal life - without a wound infection and without a tampon in the abdomen. It will only get worse if a person is taken away from the operating room ten minutes earlier than necessary, and then complications begin.
Often, in such a case, they parry that if “everything is done according to science,” it turns out “too long.” No, in fact, “too long” is the time it takes to correct the consequences if the work was done in a hurry and without proper professionalism. Recovery after infection is a real shock for the patient himself and his family, and this will inevitably affect his work. Repeated surgery, in which a forgotten tampon is cut from the abdomen, is a much more serious intervention, and it will be necessary only because the person was first operated on in a hurry.
When programming, if you have to go to five code regressions due to the fact that someone wrote it in a hurry, there is no need to talk about "saving time". On the contrary, changes are made longer. The work is not “done” until it is done correctly. If the team had to spend hours and days on correcting mistakes after “rough readiness”, then this is the lost time that could be spent on another, useful work. This is a lost profit.
Such errors give wavy consequences and lead to long-term losses of time and money, and sometimes to the loss of customers. Additional stress falls on the shoulders of the engineers themselves; low morale, high turnover of personnel. From here - more and more rigid screwing up and the further decrease in morals and an involvement in work.
Technical duty as a metaphor
Whenever you turn to the topic of gradual refactoring, someone will surely remind you of a technical duty. They will say: "we have rolled out such terms that we just need to cut corners." They will add that in this case the team deliberately accumulates technical debt, guided by the needs of the business.
Those who say so do not understand this metaphor, and perhaps no metaphors at all.
The metaphor is not intended for a complete and exhaustive description of the thing being characterized.
Metaphor helps in general to make an impression about any aspect of this thing.
People tend to replace the thing with its metaphor, and then operate with metaphor as if it and the
described thing are the same thing. No, this is not the same thing. Point.
In addition, it is common for people to interpret the metaphor expansively beyond its original context. Thus, the meaning of metaphor is blurred, and it becomes less and less useful.
Ward Cunningham proposed a technical debt metaphor describing customer interaction in the financial industry. He looked for a suitable metaphor for precisely this context, in order to emphasize how the gradual realization of possibilities helps to create a feedback loop, during which the program is constantly optimized. He did not mean to cut corners in order to create the illusion of rapid development.
The original concept of the technical debt metaphor implied that the code is necessarily kept clean. People who understand the problem left in the code move step by step towards solving it, and the code will always be careful enough to make such gradual improvements in it. We are not talking about the fact that some reasons of a technical nature can serve as an excuse for why the code spoils and requires constant corrections.
Cutting corners in order to get the job done quickly is not an accumulation of technical debt. This is the usual quickie.
Who is in charge?
To achieve fast delivery, you need to get rid of problems at work to the maximum. One of these problems is peculiar code. You can get rid of this obstacle step by step, having learned working self-discipline. In this case, it does not matter how you work - according to the “waterfall” model or according to the “Ajail”. We choose how to work whenever we touch the keyboard.
I summarize. If you work correctly, including cleaning up the ends, it will only benefit the client, sponsors, managers, those who will support our code in the future and, of course, ourselves.