If you haven’t heard of the story How to lose $172,222 a second for 45 minutes, go ahead and read it now. I will wait! This is an good example of how technical debt can cause major problems in the long run.
What is technical debt?
The definition on Wikipedia describes perfectly my understanding of the concept, its common causes and consequences:
The debt can be thought of as work that needs to be done before a particular job can be considered complete. As a change is started on a codebase, there is often the need to make other coordinated changes at the same time in other parts of the codebase or documentation. The other required, but uncompleted changes, are considered debt that must be paid at some point in the future.
Common causes of technical debt include:
- Business pressures
- Lack of process or understanding
- Lack of building loosely coupled components
- Lack of tests
- Lack of documentation
- Lack of collaboration
- Parallel Development on two or more branches
- Delayed Refactoring
- Lack of knowledge
The build up of technical debt is a major cause for projects to miss deadlines. It is difficult to estimate exactly how much work is necessary to pay off the debt. For each change that is initiated, an uncertain amount of uncompleted work is committed to the project. The deadline is missed when the project realizes that there is more uncompleted work (debt) than there is time to complete it in. To have predictable release schedules, a development team should limit the amount of work in progress in order to keep the amount of uncompleted work (or debt) small at all times.
So what can I as a developer do to keep the technical debt to a minimum?
When writing new code
Use coding guidelines, design patterns and practices to provide a good code quality that is easily readable and maintainable.
Each programming language has its own coding standards and companies or projects usually define their own within an organization or team. Simply by sticking to these rules can helps us minimize technical debt on the long run.
Document the code so that others can understand it.
Provide clear comments in the code.
Write wiki pages.
Tests and more tests
Tests are essential to ensure the correct functionality during development but also when the productive code changes.
Writing tests when implementing/changing a functionality or fixing bugs assures for the future that when someone changes the code and possibly breaks it, it will be immediately noticed and can be corrected on time.
I often use Test-driven development to write a failing test first, followed by implementing the necessary changes in the productive code and finally adjusting the test to succeed. By using this method, I can make sure that the implementation is correct and that it is covered with tests for future modifications.
When maintaining existing code
Identify code smells
First step is to identify the places in the code where a possible problem might be hidden.
Jeff Atwood has written a great post about Code Smells which I highly recommend that you read and use it as a reference.
If you see a code smell while fixing a bug or extending a functionality and improving it would not take a long time, do it!
We all know The Boy Scout Rule: „Leave the code cleaner and better than you found it.“ and this is my motto. If I touch a code, I always leave it in a better shape than it was before.
If improving the code will take longer, keep a list which is available to the team, plan it in your iteration and do it but don’t wait too long or it might be too late.
I keep a list of the places in the code where improvements should be made but fixing it would take longer. This list can be used to plan bigger refactoring sessions in the next increments.
What are your recommendations on minimizing technical debt?
- Technical debt on Wikipedia
- Clean Code by Robert C. Martin
- Refactoring: Improving the Design of Existing Code by Fowler, Martin
- Working Effectively with Legacy Code by Feathers, Michael