In the previous article, we looked at the macro trends that make tech debt inevitable. However, even though tech debt is a fact of life, technical bankruptcy doesn't have to be. So this time, let's look at the methods we can employ to avoid technical bankruptcy and save everyone a lot of grief, time, and money.
Technical debt doesn't necessarily lead to technical bankruptcy. But it is where we'll end up if we don't fight the micro-trends that push high-growth software companies towards it.
Companies typically don't take the right measures to avoid technical bankruptcy. They simply accept that it'll happen one day, and that when it does, they'll refactor their entire codebase in a giant project to deal with it. But, of course, these projects rarely go according to plan.
Even though there is little we can do about the macro trends that make tech debt inevitable—we cannae change the laws of physics, as a fictional Scottish spaceship engineer might've said—there are plenty of ways to avoid the dreaded technical bankruptcy. To separate effective from ineffective solutions, we need to gain a deep understanding of the forces at play and their roots in sociology, criminology, and game theory.
Visible signs of crime, anti-social behavior, and civil disorder create an urban environment that encourages further crime and disorder, including serious crimes.
For our purposes, we can boil things down to this: technical debt breeds more technical debt. Tolerating even the smallest of offences will lead to it becoming acceptable behaviour and it will spread to the rest of your codebase like a crimewave.
As we learned in the previous article, software entropy is forever increasing in any growing system. Therefore, so is technical debt. This makes it extremely hard—even impossible and unwise—to fix all the broken windows in your codebase and prevent a tech debt epidemic.
The tragedy of the commons is an economic problem in which every individual has an incentive to consume a resource at the expense of every other individual with no way to exclude anyone from consuming. It results in overconsumption, under investment, and ultimately depletion of the resource.
Software engineering teams are typically rewarded for delivering as quickly as possible on the tasks they were assigned. The resource they consume is time. They're incentivised to go as fast as possible and therefore often take shortcuts, thereby creating technical debt which subsequently becomes everyone's problem. However, since everyone is incentivised to keep shipping new features at pace, engineering teams won't have any incentive to step up and pay back tech debt. It's the prisoner's dilemma.
The prisoner's dilemma is a paradox in decision analysis in which two individuals acting in their own self-interests do not produce the optimal outcome.
Both concepts are cases of self-interest harming the common good. Combined, they explain why tech debt usually remains unaddressed until it causes the whole software development machine to grind to a halt. Peter Merel ran through an interesting simulation of this problem in his article "The Tragedy of the PMO".
Once they go technically bankrupt, companies have no choice but to pay back technical debt, and because they didn't repay it continuously as they were shipping new features, they have to do it all in one massive project . . . or throw the code away and start from scratch.
The problem with this approach is that the more complex and larger a project is—especially when it's riddled with technical debt—the harder it is to accurately estimate tasks. David Bailey has written a great piece to help you tackle this: What NOT to do When Rebuilding your Tech.
Technical debt doesn't arise out of malice. And incompetence isn't as big a contributing factor as you might expect. We can't just tighten the screws on our engineering team and expect tech debt to go away. You probably know someone who's tried this approach and failed. In fact, none of the typical solutions to tackle tech debt work.
Organizations which design systems [...] are constrained to produce designs which are copies of the communication structures of these organizations.
We expect software engineers to manage tech debt properly. Yet the systems they design are constrained by the company's org structure—which they have little control over. Any changes in company structure and the way it communicates have to come from the very top, and if we're lucky, the people at the very top understand tech debt and take it seriously. But if they're like most people and they don't get it, we're in trouble.
Add to this the fact that companies often suffer from organisational debt, which Steve Blank deems even more deadly than technical debt, and it's clear why engineers are set up for failure.
[...] Premature optimization is the root of all evil (or at least most of it) in programming.
The Art of Computer Programming by Donald Knuth
Knuth's principle was originally concerned with the time code takes to run, but it is also a foundation of the Lean Startup and Agile methodologies, applied by so many modern engineering teams at high-growth software companies—and rightly so.
It explains why taking on tech debt to avoid the horrors of premature optimisation is often the right choice, a topic you can dive into with our article about how to define effective tech debt budgets. But tech debt needs to be managed carefully, especially once a company reaches product-market fit. Timely optimisation is fantastic but it's also extremely hard to do when every incentive pushes you to quickly ship new features instead see previous article).
Never, ever, think about something else when you should be thinking about the power of incentives.
The laws, rules, principles, and theories we've discussed all have one thing in common: they describe a set of existing incentives and their consequences. But the solution to the vicious cycle of tech debt is to fix a very specific set of incentives, to turn the tide in our favour.
It's likely that around 20% of the tech debt in your codebase accounts for around 80% of your problems (e.g. bugs, outages, etc.). As revealed in our article about how to define your tech debt budget, Microsoft Research has shown that while active files only make up 2–8% of the total systems, they are responsible for 60–90% of all defects. In other words, you don't need to tackle all your tech debt at once.
Given enough eyeballs, all bugs are shallow.
Keep pull requests small so they're easy to review, and make sure the code is reviewed by enough of the right people (hint: probably people who own this code). That way, you'll catch most bugs before they even make it to production.
This one's simple. During Friday demos, don't just applaud the engineers who shipped new features. Cheer for the unsung heroes of tech debt: the people who refactored this nasty function, fixed that bug, reviewed these pull requests, and saved you from the seemingly inevitable destiny of technical bankruptcy. It's one of the stops on your journey towards an engineering culture of ownership, and a healthy codebase.
Company leadership needs to understand how tech debt impacts the whole company and the role they have to play in it. Only then will they take it seriously. As software engineers who understand technical debt, it is our responsibility to communicate it across the entire business.
We'll talk about this in an article very soon, but in the meantime, take a look at Martin Fowler's excellent piece, 'Is high quality software worth the cost?'.
Notice how none of the advice above requires additional engineering work. In fact, it breaks the tech debt problem down into smaller habits that, if properly followed, will make everybody's job easier, faster, and more enjoyable.
Champions don't do extraordinary things. They do ordinary things, but they do them without thinking, too fast for the other team to react. They follow the habits they've learned.
Charles Duhigg, The Power of Habit: Why We Do What We Do in Life and Business
Change small habits over time and your engineers will ship better code faster, you'll have happier customers who'll refer more leads . . . and you'll beat your competitors.
To help you acquire these good habits, we built a free VSCode extension to continuously track and pay back tech debt. Get started now before it's too late!