Understanding tech debt
Where does technical debt come from ?
Before discussing techniques to manage technical debt, it’s important to understand where it comes from. It’s not just the result of shortcuts taken during development.
6 min read
Let’s recall our definition of ‘technical debt’ from the previous chapter:
Technical debt is code that has become a liability and makes it harder for companies to achieve their goals.
This definition helps us turn a rather abstract question into a clear one — how does code end up becoming a liability ?
To answer this, let’s picture an imaginary hyper-growth startup called Footsize. Footsize is winning in the market, hiring and growing its customer base aggressively. What was once a 10-person team working on a simple product is now a unicorn with hundreds of engineers and a product portfolio.
But Footsize is facing serious challenges: it’s struggling with technical debt across its codebases. Productivity is dropping, more and more bugs are reaching production, and engineers are growing increasingly frustrated.
We might be tempted to look at it with contempt — how could they let things get this bad ?
It’s actually completely normal for growing companies to accumulate technical debt. To understand why, let’s explore what makes code a liability.
Technical debt is a function of business context
First, we need to understand that bad code isn’t necessarily technical debt. Technical debt doesn’t exist in a vacuum.
Picture the worst spaghetti code you could imagine. It’s full of bugs and is impossible to understand, much less extend. Even the person who wrote it in the first place can’t make sense of it anymore.
You’ll definitely find this kind of spaghetti code at Footsize. But it’s not necessarily technical debt.
If Footsize doesn’t need to change this code, it doesn’t matter that it’s hard to extend. And if no one uses the feature implemented by this code, it doesn’t matter that it’s buggy.
Code becomes technical debt the moment it prevents companies from achieving their goals. Until then, it’s just bad code.
Of all the bad code at Footsize, only some of it is a liability: the code that’s causing productivity to drop, users to run into bugs, and engineers to get frustrated.
This is foundational to understand where technical debt comes from.
Origin #1: Technical debt emerges when business context changes
Engineers write code thinking about what’s needed today and what might be needed tomorrow. We can’t anticipate every future requirement, and even if we could, we’re under time constraints and need to make trade-offs. So we try to strike the right balance between all these concerns.
Back when Footsize was a team of 10 people, they only had a rough idea of what the future might hold. They built the first version of the product as best they could, then time went by, business context changed, and technical debt emerged.
For example, the monolith that worked great at the start couldn’t support a user base 10 or 100 times larger. And an experimental feature blossomed into a promising opportunity that Footsize now wanted to pursue, but the technical foundations couldn’t support this expansion.
Technical debt big and small appeared all over the place as Footsize’s goals and the context it operated in changed.
This is how a lot of technical debt is born. And it can’t be avoided, simply because no one can predict the future.
The fact that Footsize is struggling with technical debt is a result of its success. But it’s also the result of some operational failures — not all technical debt is unavoidable.
Origin #2: Technical debt is created when teams fail to plan effectively & deliver on these plans
Development teams rarely operate optimally; there’s always room for improvement. These failings result in technical debt that could’ve been avoided.
We can break these down into planning failures and delivery failures.
The aim of planning is to define clear goals and articulate how to achieve them.
Without these, we’ll write code only to realise later that it didn’t accomplish what we wanted to accomplish. We’ll need to refactor some of that code to correct these mistakes. In other words, we’ll have created technical debt because we planned poorly.
This is a common source of technical debt, one Footsize is very familiar with. Any number of things can go wrong when turning an idea into a project:
Users’ goals can be misunderstood by the product team
The solution created by designers can fail to meet users’ goals
Engineers can fail to outline an adequate architecture and testing strategy
Teams can allocate too little time to refactoring existing code to fit the new business context
And much much more
All these failures result in code that isn’t fit for purpose and that becomes a liability for the company later on. Technical debt can often trace its origins back to before the code was written.
Planning effectively is only half of the story — we then need to deliver on these plans.
Again, many things can go wrong when shipping a software project:
Lack of knowledge and experience can lead to poor implementation choices
Sloppy code review can fail to catch mistakes early and fix them before release
Poor collaboration around unforeseen challenges can result in subpar solutions
Inadequate tooling to develop and test code can force engineers to write code without confirming it works as intended
And much much more
While the failures are diverse, the result is the same: code which doesn’t deliver on the company’s goals and needs to be refactored to ship the next iteration — technical debt. This happened often in Footsize’s history.
We’ll share best practices for effective planning and delivery in future chapters.
Origin #3: Technological shifts produce technical debt as a side effect
Every company’s software depends on factors outside of their control: the ecosystem they’ve decided to build upon.
These dependencies can become the source of technical debt. A company can fail to keep its dependencies up to date and end up running outdated code that stands in its way. Other times the technology itself can become obsolete, replaced by new more capable solutions, and the very foundations the company built upon become a liability.
This happened to Footsize — they decided to build upon AngularJS before it was discontinued a few years later, turning their entire frontend codebase into a tech debt nightmare. And just think of all the financial systems running on COBOL.
Although it’s slower-moving than the business context, the technical context does inevitably change over time, creating technical debt in the process.
Technical debt comes from a mismatch between code and business goals.
Some technical debt is unavoidable because business context changes in unpredictable ways. These changes turn code that was once perfectly fine into obstacles to the company’s new objectives.
Some technical debt is avoidable because it comes from failures in planning and delivery. These result in code that’s a liability from day 1, or that becomes a liability much sooner than it should’ve been.
Some technical debt is the result of an evolving technological landscape. Most technologies either become obsolete or superseded by better solutions, and companies have to transition over to the latest tech to reap its benefits.
In the next chapter, we’ll explore the impact of technical debt.
It’s often thought of as a problem affecting engineering teams, but we’ll break down its impact across the entire company.
Subscribe to receive the next chapter in your inbox.