How tech debt kills your projects



Each project requires sacrifice. The main thing is not too big. The Mail.Ru Cloud Solutions team translated Alex Staveley's article on the downsides of technical debt and its ability to destroy even the most successful project. Author’s warning: this article doesn’t have as much practice as we would like, but it may lead to thought.

Do not confuse technical debt with poor engineering


The concept of technical debt is used in software development to express the additional complexity that is added to the project due to the choice of worse, but faster solutions. It is similar to financial debt. Take a loan to quickly achieve a goal, but then be sure to repay it. Otherwise, the loan with interest will grow - and in the end you run the risk of going bankrupt.

As with financial loans, some technical debt is acceptable. In the end, if you look too long for the perfect solution, your customers will go to someone else.

At the same time, if you take too many technical debts and do not pay them, then software entropy grows with time - it also happens with loan interest. Ultimately, your product will begin to stagnate. Some new task, which should be solved in just a month, suddenly takes three months, then six months, then only a few people in the entire company can do it in six months, then some of them leave, then ...

The analogy does not work only in that that technical debt is too often equated with poor engineering. But poor engineering solutions fall into a different category.

In the case of technical debt, good tactical decisions have been made with the full understanding that short-term priorities are worth such a sacrifice.

When it becomes clear that such a decision was good tactics at one time, it is much easier to understand that you need to refactor and pay off technical debt.

When the term is used as a polite synonym for poor engineering, a debt recovery strategy becomes difficult. And it is even more difficult to create, because first you need to convince people that there is some kind of “bad engineering”. Then you need to convince people that this is causing problems. Then you should consider the best approach to refactoring and its costs.

Finally, you must convince all parties concerned that the investment is worth it, and keep your fingers crossed that you have not offended any ego along the way. It's like trying to win five away matches when every game has a chance against you.

,


So, what are the signs that your technical debt (intentional or accidental) is too high - and not far off is a bankruptcy petition?

Let's speculate. In the Agile world, we want to develop and release product updates in short cycles, getting quick feedback from customers, and repeating cycles again. This is only possible with a large number of high-quality and well-designed automated tests that work quickly and give confidence that no change has broken anything. It does not matter what the breakdown of the tests into categories is: 68% modular and 32% integration or 91% modular and 9% integration, tests should be performed quickly and reliably. Otherwise, the releases will become problematic and you will not be able to do them regularly.

This means that working on the Agile methodology will be very difficult, even with the highest quality backlog grooming sessions, which analyze the set of requirements received from the business and formulate tasks for development.

It is a technical duty, whether intentional or accidental, that usually prevents developers from writing good tests.

Now there are many tools for measuring technical debt and its integration into the beautiful SonarQube panel , but usually they take into account only trivial things - unused imported code and the like. Who cares? Such trivial things will not hurt anyone.


Technical Debt in the SonarQube Dashboard

The real technical problems with debt are when development slows down, changes are made difficult, errors are fixed, functionality is added, because testing becomes much more complicated. Unfortunately, these technical problems are unlikely to be automatically shown to you by tools such as IDE, PMD, or Checkstyle. As a rule, they are much deeper in nature - closer to architectural problems.

A few examples:

  1. The lack of encapsulation and immutability of the data, leading to enormous cyclomatic complexity, unpredictable code execution paths and difficulties in predicting impact.
  2. Impedance mismatch, i.e. data type mismatch that is provided for in the application language and in the supported data model.
  3. Lack of modularity and too strong adhesion of program components.
  4. Lack or poor use of patterns.
  5. A proprietary language introduced without IDE support, without a mechanism for simple unit testing or code debugging. At Stack Overflow, they don’t know anything about him.
  6. Spawning threads and asynchronous call paths when there are better approaches that are much easier to test

It is here that the analogy of technical and financial debt is violated. If you have an architectural duty, you have big problems. If it is more superficial, then the problem is not so great.

In financial loans, there is no such fundamental difference in the quality of debt. If you do not compare the debt to a friendly and pretty bank with which you have a good relationship, and the debt to a crazy bouncer, who will come to your home with a baseball bat.

There is a technical debt. What to do?


So, you are approaching the credit limit, what should I do? First, ensure the reliability of the tests. They should test key functionality and be maintainable. This is more important than speed. If there is no reliability, you cannot release product updates. What is the use of five-minute tests if no one is sure that the tested functions will really work.

Then, when you are confident in the tests (even if they are ugly end-to-end tests), you need to get the tests to work quickly. Then start refactoring. End-to-end tests should facilitate changing call paths; for example, to split a monolithic structure, you can use the Sprout method \ class . This will help move on to the classic test pyramid .

Now you need to understand why it is so difficult to make quality tests. Too strong coupling of program components, poor exception handling, poor separation of the program into parts (poor decomposition) - the list can probably go on and on.

Understanding the reasons why your code is difficult to cover with tests is a key architectural and engineering skill, since it requires not only an understanding of the complexity of the program, but also knowledge of how to reduce this complexity. Then reducing technical debt will help simplify the code for testing and so do good and quick tests. As a result, we begin to win the battle with the possible stagnation of the project.

Finally: How Agile Creates Technical Debt


The Agile development methodology has become such a common standard that the “fake” Agile problem arises . We see books, courses, blogs with a detailed description of new concepts, such as story points (stories), diagrams of combustion tasks, stand-ups.

All this is good, but little attention is paid to the quality of development. Without it, architectural problems will inevitably arise - and a code will appear that is poorly tested, although you compose perfect story points, formulate definitions accurately, translate business cases into programmer tasks very effectively and paste yellow pieces of paper into the right places on the board.

This is good and useful, but compared to the quality of development, it’s almost a trifle. Such activity is easily visible from the outside, but in itself never reflects the complexity of technical debt. It is the ratio of technical debt to development quality that determines how easy it is to write testable code and ensure regular short iterations, which is the goal of Agile. Is not it?

When a child tries his strength in some kind of sport, we always tell him: “If you start to lose, never give up, fight to the end!”. Technical debt is a natural phenomenon, every project in this world has it. Your task is to keep it under control, and when it grows too much, come up with a way to get around it and eventually learn from this.



What else to read :

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


All Articles