Rating: 7.1/10.
Technical Debt in Practice: How to Find It and Fix It by Neil Ernst, Rick Kazman, Julien Delange
Fairly short book that examines technical debt, its causes, and ways to mitigate it. It is nontechnical and does not provide much specific code, languages, tools, etc. It is written by several academics; many of its sources come from interviews with industry experts. The authors have not themselves worked as software engineers, instead examining the phenomenon of technical debt from a sociological perspective. Because of this, the practical usefulness is relatively limited, as most of their advice is fairly generic. More concrete guidelines or examples would have helped make the book more useful to practitioners.
Chapter 1. Technical debt is a financial metaphor for what happens in a codebase, and it can be taken deliberately for strategic reasons or inadvertently. You can have various forms of technical debt, including social debt, documentation debt, etc.
Chapter 2. Technical debt can be thought of as a short-term solution that needs to be repaid later. This can be beneficial, as in the case of Facebook’s use of PHP, which allowed it to grow quickly until it had enough resources to fix and optimize by writing a transpilation system. It is also advantageous in situations where there is a critical deadline, making the code much more valuable if shipped before this deadline, or if the system is expected to be near the end of its life and require relatively little future maintenance and development.
Chapter 3. Requirements debt is poor management of requirements, such as what the software is supposed to do and why. You should have processes for prioritizing requirements and context around why each feature is required.
Chapter 4. Design debt is poor management of dependencies and interfaces between them, leading to modules with multiple responsibilities and high coupling. These dependencies can be measured either explicitly by imports between modules or implicitly by code that simultaneously touches multiple files. This should be fixed by refactoring, and there are tools recommended to use metrics to justify the refactoring effort to management, such as the lines of code saved versus the refactoring effort required.
Chapter 5: Implementation debt includes the use of undesirable or deprecated language features or libraries, and code duplication is a common type of debt. To avoid implementation debt, it is recommended to use tools to automate simple checks and to follow good practices around code reviews and maintaining high quality.
Chapter 6: Testing debt. A lack of tests inevitably leads to bugs that take more time to fix later. It is important to have a suite of unit and integration tests, along with tools to ensure that tests are correct and have reasonably good coverage.
Chapter 7: Deployment debt is issues that manifest in deployment mistakes and production being broken, such as error-prone manual processes, difficulty detecting bugs, and difficulties in staging and rolling back changes. Recommend having metrics to observe system health automatically, as well as automated gradual deployments, so that bugs are not exposed to all users; kill switch to disable features without requiring a rollback is useful.
Chapter 8: Documentation debt is when knowledge is undocumented, it is crucial to prioritize documentation that is more valuable than its cost. Therefore, avoid creating documentation that nobody actually reads. Write documentation alongside the code so that both can be reviewed together, and use tools to prevent the documentation from becoming outdated.
Chapter 9: Machine learning systems have unique forms of tech debt. Documentation is especially important because many decisions are based on past data analysis, and there is greater difficulty in integrating with other systems (especially since most software engineers do not understand ML systems well), and much of the complexity lies in the configuration rather than the code.
Chapter 10: Social debt includes many forms of breakdown in communication, trust, knowledge sharing, or the proliferation of harmful behaviors. It often leads to technical debt, project bugs, and delays.
Chapter 11: Communicating to business people – the impact of tech debt includes more time to develop new features, lower developer productivity and happiness, and the understanding that it is unrealistic to eliminate tech debt completely. It is more about the fact that tech debt takes away future options to modify the codebase.
The book concludes with interviews from senior software engineers with various perspectives. The first interview is with a software engineer working on a telescope scientific project that involves handling large data sets and numerous users. The challenges include upgrading scientific packages to newer versions, using libraries for various languages, and balancing the trade-offs between convenience, such as Python, and lower-level languages for performance-critical tasks, while integrating them effectively.
The second interview features a developer who worked on Datadog open-source projects. In this team, the number of developers shrank from a large group to only three, necessitating the prioritization of tech debt over new features. Due to the small team size, fixing the debt had to be carefully planned to avoid wasting time on refactoring when removing the feature entirely was a better option.
The third interview is with a developer of a crypto application for embedded devices. The application was engineered in a way that required refactoring to stay aligned with modern best practices. However, with several hundred customers needing backward compatibility, the team ended up maintaining both legacy and new versions in parallel, while the older version is slowly being deprecated.