18 November 2017
Technical debt is an overused and lazy metaphor
"Technical debt" is a popular metaphor among development teams, particularly those seeking to win support for large-scale re-working of solutions.
The phrase was originally coined by Ward Cunningham and is widely used to describe the implied cost of choosing a quick solution now over a better approach that will take longer to implement. This creates a “debt” that can accumulate “interest” over time, making it much more difficult to implement changes to a system over time.
The metaphor is often used to describe how bad code design undermines productivity to non-technical audiences. Unfortunately, it’s generally used as a very broad brush that does not help in understanding why these problems occur or how to deal with them. At worst, it can risk trivialising them.
Is this “debt” or is it just “mess”?
The debt metaphor is often lazily applied as a catch all term for the “mess” that inevitably accumulates in a long-lived code base. This is caused by influences such as short-sighted design decisions, messy code written by inexperienced developers, the inevitable creep of technical obsolescence and the normal complexity which is part and parcel of all system development.
It's important to understand a nuance behind Ward Cunningham's original metaphor: he was not suggesting that teams could deliberately write bad code with the intention of fixing it up later. The debt metaphor was originally coined to describe how a code base is undermined over time by evolving requirements:
"I'm never in favour of writing code poorly, but I am in favour of writing code to reflect your current understanding of a problem even if that understanding is partial."Design problems are inevitable if you are working on a partial understanding of a problem. This is the innocently-accumulated debt that is caused by a system’s design being out of step with the business processes that it implements. This suggests that technical debt a natural and inevitable part of normal agile development, but it does rely on your ability to pay the debt back by writing code that is clean enough to refactor.
Development teams vs the world
It’s easy to exploit the debt metaphor to reduce the perceived impact of bad design decisions. Teams are encouraged to build “quick and dirty” solutions in the false belief that the business will be prepared to invest in re-working it later. The reality is that it is notoriously hard to win support for a re-write of existing features.
This can create an unhelpful dynamic where teams feel that they are “owed” time by the business. Teams argue that the code base is in a mess because too little investment has been made in good design and technical best practice. Over time this can pitch teams against commercial stakeholders and management teams.
In extreme cases, a war of attrition can open up between development teams who want to do something “properly” and the commercial stakeholders who want to ship new features. A technical compromise is not necessarily “debt” that needs to be paid back later. It may be the only commercially viable of delivering a feature.
Should we just accept the mess?
A debate about technical debt is only worth having if we understand that it might not be worth paying it down. In many cases, a messy and difficult code base remains the commercially optimal way of delivering functionality. The fact that it is riven with recklessly accumulated debt is not enough in itself to justify reworking it.
Some years ago, Nicolai Josuttis gave a keynote where he suggested that we should “accept that bad code quality is common and react accordingly”. This flies in the face of the “clean code” agenda that suggests that we are evolving a better understanding of good practice that will improve the quality of code bases over time.
He advocated different techniques to deal with the reality of bad code, such as separate feature and refactoring teams, tolerating cut and paste and using “experts” to fly in and mop up after less talented developers. Personally, I find this too depressing a proposition to consider – surely we can do better than this?
Code quality is essentially an up-front investment in a better future. You need developers who understand the various techniques and a business that is prepared to tolerate a perceived short-term drag on productivity. It can be difficult to win support for code quality in the face of real-world commercial pressure.
“It’s not a fair fight”
The debt metaphor may be a useful tool for discussing code issues with non-technical audiences, but this isn’t the same as winning support for technically-driven work. Commercial stakeholders will always have a surprisingly high tolerance for system mess. They’re also better at arguing their case than the average developer.
All software development is a trade-off between competing interests, e.g. the people who use the system, the sales teams who have targets to hit and the developers who maintain the code. Technical concerns are often pushed aside by commercial concerns that are better articulated and couched in terms that the rest of the business can understand and identify with.
The challenge for developers is that commercial stakeholders tend to have more experience in framing and winning arguments. As a seasoned CTO once explained to me – “it’s not a fair fight”.
How can developers win this argument? Talk of technical debt and the need for “clean code” just aren’t enough on their own. A product manager who is under pressure to release a feature won’t care about whether SOLID principals have been applied to the underlying solution.
Developers have to evolve their arguments by learning to use the language of commercial stakeholders. It’s not so hard to put some tangible numbers on the commercial impact of a poor quality code base. There’s the extra cost of on-boarding new developers, the greater likelihood of support incidents and the drag this places on development. This has to be traded-off against the extra cost of time taken in redesign.
In a developer’s mind the trade-off is a no-brainer. Commercially-driven stakeholders will be assume the opposite unless presented with some hard evidence. It’s up to developers to learn how to express their arguments in the cold, hard numbers that will win the argument rather than expecting to win the day with debt metaphors.