A primer on technical debt and how to deal with it
Or why you cannot afford to skip continuous refactoring
Posted on November 23, 2017
Whenever a developer is about to implement something, there are basically two approaches:
The first approach usually works just as good as the second one — at present. The price we have to pay comes later; when the code needs to be modified. This penalty can take many forms, from making the code harder to read and understand, to becoming an impediment that completely hinders further development.
Over time, these shortcuts compound and build up what is commonly known as Technical Debt.
The term Technical Debt is a metaphor coined by Ward Cunningham, an iconic American programmer and one of the authors of the Agile Manifesto.
Just like financial debt, technical debt incurs interest payments. Which typically manifest themselves as longer lead times further down the road, due to the extra effort needed to cope with the effects of the quick-and-dirty approach taken earlier.
Think of technical debt as borrowing from our future speed of delivery in order to increase our speed today.
And, just like with financial debt, it's perfectly acceptable to take on technical debt under certain circumstances. It can allow us to exploit a market opportunity sooner, or to meet a hard deadline. As long as the interest we incur leads to an investment worth more than it costs we're fine.
The problem, though, is that unlike financial debt, there's no clear net debt statement for technical debt. Sure, there are tools available that can provide some help in assessing it, but bigger design flaws usually aren't measurable.
These undesired side-effects tend to manifest themselves at the least convenient time possible, often slowing down the team considerably.
Technical debt may arise from a multitude of situations, both internal and external:
|Business||Market opportunities or technology proposals||Legislation or industry regulations|
|Technical||Developer decisions||Vendor dependencies and 3rd party code|
In the top left corner, we have the business opportunity mentioned earlier. But also things like infrastructural changes or rollouts of new software. Typical examples of the latter ones are cloud migration and new ERP software.
Next, we have legislation and business regulations. A current example of the former is the EU's General Data Protection Regulation (GDPR), with heavy fines waiting for those companies that don't comply. An example of the latter is the Foreign Account Tax Compliance Act (FATCA). While not legally obliged, most non-US financial institutions had to opt in or lose business.
While most of these causes might be conceived as well-known, thus being communicated well ahead of time, they might have far-reaching consequences that are difficult to overlook.
The lower right corner, vendor dependencies, poses a similar problem but often on a smaller scale. Typically, there are only one or a few systems that get affected. But on the other hand, the changes can occur without any warning and have dramatic consequences.
However — in the end, everything tends to end up in the lower left corner: Developer decisions. And regardless of how the team ended up in this situation in the first place, we can drill down even further. There are four distinct origins of trouble here:
|Deliberate||"We don't have time for design"||"We must ship now and deal with the consequences"|
|Inadvertent||"Why do we even need to write tests?"||"Now we know how we should've done it"|
While these situations often originate from events beyond the team's control, we developers have a tendency of bringing technical debt upon ourselves as well.
Practices and craftsmanship recommendations like Test-Driven Development and Clean Code have been around for years, but I still find that while everyone buys into the ideas, there's still a lot to be desired when it comes to practice.
This kind of technical debt — messy code written by developers ignoring best practices and coding standards — can turn an organized codebase into a bowl of spaghetti in just a couple of months.
That said, not all messy code comes from ignorance or sloppiness:
Tight deadlines are more often than not the underlying factor that forces teams to cut corners, paired with stakeholders' inability to understand the importance of continuous refactoring.
Feature development is generally prioritized over fixing the technical debt, and once a working feature has been deployed to production, the incentive to spend money on improving the quality of the underlying code is gone.
As a stakeholder, you might not care what the code looks like, but you care about your team's ability to produce. And while a concentrated refactoring effort for code that's already been shipped might be a tough sell, the suggestion of doing continuous refactoring to speed up further development probably isn't.
There should always be an ongoing dialog between the business and the development team, preferably facilitated by a product owner. Together, we can choose to continue paying the interest, or we can pay down the principal by refactoring a quick and dirty design into something more sustainable.
Focus on the parts of the system that would benefit the most, but don't limit the pursuit of improvement to the codebase alone. Perform regular evaluations of the overall architecture and all surrounding processes as well, technical as well as product governance related ones.
This includes everything from source control branching strategies, to build server configuration, to routines for deployment and product releases. Even your agile way of working. Are these processes helping or hurting the team?
Keep in mind that the mere fact that a process exists often justifies its continued existence, regardless of if it's still being adequate or not.
Finally, remember that just like brushing your teeth, paying back technical debt is a continuous process. And just as brushing for three hours straight twice a year won't suffice, an isolated refactoring period during summer or Christmas break just isn't enough.
Join my mailing list and get notified whenever a new post is out.
Topics range from team development, to application development strategy, to productivity tactics.
I won't spam you, and you can unsubscribe at any time.
A welcome email is on the way – please check your spam folder if it doesn't show up.
And to ensure that you don't miss anything, add firstname.lastname@example.org to your trusted senders.