Technical Debt Management / Habrahabr
On the problems of software development, its evaluation, cost control, testing written a huge number of books. I want to share with you the proven practices that helped me as a technical manager to keep technical debt under control in a growing project.
Maintain flexibility in the right places
Design the software just like you would design a building. Something in construction is moving slowly, something is fast. Some components, for example, furniture or painting of walls, are not directly related to the building itself. It is very difficult to change the angle at which the walls are located to each other. It is necessary to prioritize.
Understanding what can be flexible in the program and what is not refers not only to the current requirements, but also to the future. That's why it's so hard to create software. You are not just delivering your technological product, you are trying to predict the future. And the future is obscured, there is always the risk of premature optimization. It will be necessary to make a choice: which component is fundamental, and which one can be easily changed.
The word software (literally "soft product", appeared as a counterpart to "hard hardware") distorts the essence of the concept, because it implies flexibility in everything. Flexibility in everything is an ideal to which one should strive. However, the truth is that a more rigorous system with very closely related components is much easier to build. For example, it can be argued that in a monolithic application, the elements are interconnected more strongly than in a set of microservices. The obvious advantage of a monolithic application is its simplicity. Do you want to write at least a line of code for an application based on microservices? Examine first a giant list of requirements for data exchange, coordination and availability of system elements.
This does not mean that micro-services solve the problem of communication between modules. They link modules to a network that allows you to build clear, delineated domain boundaries, but the connection itself is inevitable.
Flexibility is expensive. I can not even count how many times I created something with the idea of how the requirements will change in the future, and then I found out that it is necessary to change the "fixed" parts, and the flexible ones do not have to be flexible. At first I thought that I was just not lucky, but now I understand that I was just wrong in planning.
Software, unlike the building, is aging differently. If the requirements do not change, the foundation will not move and will not begin to collapse, as it does with the building. The software does not wear out. However, its foundation is influenced by new requirements. Start-ups are very difficult to make the right choice. The cloud is trying to solve this problem, laying the possibility of scaling from the very beginning. Optimizing cost management and speed as you grow will require a lot of fundamental work. Even with modern cloud solutions, mechanisms for managing microservices and so on.
Refactoring for speed
Refactoring is one of the best ways to increase the overall speed of work. This has already been said a lot. In any sufficiently large code base, there is something to be refactored. The main thing is to refactor in the right place, where you need simplification and flexibility in the future. To make it look like a guessing game, it will be correct to refactor before introducing new functions.
Before you write the code, accept that it will have to be thrown away
A simple way to reduce technical debt is to understand that any code is only a temporary experiment. For example, you decided to create a separate code branch and quickly sketch the prototype, which you can implement. Even if everything is fine with this feature, you will have to write the code anew as it should, and throw out the old one. Such prototyping is specific and carries many risks: some people in your team will have to lower their standards. However, this method will save your time.
Work with the tests and analyze the code
Testing is a way of life, a sacred practice. Even in small projects, testing saves more time than the process itself takes. Sometimes it can be seen right away, sometimes later.
The company should make a code review. It does not matter how many tests you write, do you know how to refactor. Other people will notice the moments that you missed. Errors. Bugs. Misprints. Yes, anything. In many companies, three pairs of eyes check each line of code – I think this could become a general rule.
The frequency of testing and conducting code reviews should be commensurate with the harm done to the project in case of failure. The source code requires more careful testing than the interface code. Any software related to the operation of the insulin pump should be tested more seriously than any mobile application. Can you imagine a team working on an insulin pump with the slogan "Do it fast and destroy"? (the mantra of Facebook development and Mark Zuckerberg's motto "Make fast and break things").
Kill badly working features
A friend of mine, engineer Noah Thorpe, once said to me: "We pay for every line of code every day." The less code, the less you pay. When I'm working on a project, it's important for me how each feature works. I regularly gather a team to decide which features to improve and what to clean. This means at times to admit to yourself that the feature that you like simply does not work.
The ideal situation is this: you understand that the feature will not work properly even before you write the code. On the first line of protection paper prototypes and testing on users. Nevertheless, they always put pressure on you. There is always a fuss of people using the product and asking to add such awesome opportunities that you never need to implement. Or such features that you could add, but later. This is where product management and technical design meet: even if you create a new feature, it's common, you still have to pay for it.
Reduce dependencies to a minimum
You have to pay for dependencies too. Dependencies are internal and external. Internal – these are the libraries and frameworks on which your software depends. External are services with which your software is connected. From services you depend more than doubly, because libraries are usually associated with them.
Adding a library to your project, you pay for the entire library and your use of it. So, you need to justify the need for each library, each plug-in. Even the smallest. They are added quickly. If you have a balanced approach, you will be surprised how quickly you will advance.
Applying all these methods is easier if they become common principles of work in your company and a favorable environment is created for their use. Maintain a high level of code review with requests to include the code (pull request). Continue to constantly test, supporting the system of continuous integration (Continuous Integration). Monthly discuss the main features. Keep paper books that talk about the right approaches, for example, "Refactoring: improving the design of the existing code". And do not forget to read them!
It's important to clearly understand what you are building. It will be a secret shelter on the beach, a standard dwelling or a glass art museum? The answer to this question should coincide with the whole team. That's why managing a technical debt is not just the job of a technical manager or developer. This is a common work. After all, it affects every step of the product development process, starting with planning.
Courses of "Netology" on the topic: