Why I don’t condemn technical debt
Technical debt is usually discussed as something that engineering teams should avoid. This article proposes a different perspective: Technical debt is a financing tool that exchanges future cost for present speed. By considering both its interest rate and the probability that it will have to be repaid, we can distinguish useful trade-offs from decisions that threaten a product’s future development.
My background
Before we dive into the core topic, let me give you some background information about me. I’m a software engineer at heart. I like to do things the right way, and principles are very important to me, even if they are hard to justify rationally. Of course, over the years, you start to become more pragmatic. You realize that things cannot and should not be perfect all the time, as perfection (if it even exists) has its price. This development led to a new principle for me: Technical debt is not a bad thing per se. It’s a tool that we can use and that can drastically help us achieve our goals.
What is debt?
Instead of straight diving into technical debt, let’s explore debt for a bit.
Debt is an obligation that requires one party to pay money borrowed or otherwise withheld from another party.
So you get money, that you have to return at some later point in time. This allows us to make investments that we could otherwise not. Let’s think of housing. Buying a house worth 600.000 € with your own money is becoming more and more rare. Instead, you go to a bank, ask for a credit and can buy this home. Of course this comes at a price: Interest. In total, you have to give back more money to the bank than you received. But still, people do it! So it all depends on the specific conditions that you get for your credit. How much more do you have to repay, and in what timeframe do you have to accomplish that. And these conditions make the difference between a a tool that is generally recommended to use and a thing, that can lead you to total bankruptcy. So as a result, there is good debt, and there is bad debt.
Technical debt
Now I want to cross the bridge to technical debt.
Technical debt is a qualitative description of the cost to maintain a system that is attributable to choosing an expedient solution for its development.
So at one point in time, you make a decision to solve a problem in your codebase in a specific way but you think this approach will make certain things later down the line more complicated or you even have to totally redo the solution that you picked to keep your product alive. The question is: Why did you even make this decision? Two possible answers come to mind:
- We did not know that a decision negatively impacts future development
- We cut corners to be quicker
Answer 1 is not the main focus of this article, so let’s first dive deeper into point 2: technical debt that we take on deliberately.
When we deliberately pick a “worse” solution, we do so because it gives us an advantage in the present—usually speed. Shipping earlier might help us validate an idea, reach the market before our competition, or focus our limited resources on something more important. That trade-off can be worthwhile, but not every shortcut has the same consequences. Some remain cheap for years, while others grow until they slow future development to a halt. To tell the difference, we need to look more closely at the conditions attached to the debt.
Classifying different types of technical debt
We learned, that technical debt can be good and bad. Now, I want to try to build a framework that helps you find out on which side of the spectrum you are and how you can actively steer into a more favorable place.
The first dimension, can be taken directly from normal economical debt: Interest rate. When borrowing money, the interest rate tells you, how much MORE you have to pay back. This principle can be applied to technical debt as well. If I leave out a feature, that would take me 10 hours to do right now, how long would it take me to implement this feature in 1 year? Depending on the context and the evolution of the system, that number might drastically go up. For example: If you build the primitives for authentication and authorisation from the very beginning, it can be done rather quickly. But adding those two once your whole application is built can become very painful. In the other extreme, we might have a model component that is reused in our app, and we think about adding a nice fading animation to open and close the modal. It really does not matter for the effort if we add the animation now or in a year, as long as all places already use the central modal component, we can just add the animation and have it everywhere at once.
The second dimension is the assumed probability that we will have to pay back the technical debt. A feature that is never used, a product that never finds a market, or an experiment that is discarded may never require us to repay all of the technical debt it accumulated. From a purely economic perspective, investing heavily in the perfect architecture for such a feature would have been wasteful.
This means that the cost of technical debt does not depend only on how expensive repayment would be. It also depends on how likely repayment is. Combining these two dimensions gives us a simple framework for classifying technical debt:
)
Technical debt becomes more dangerous as both its interest rate and the probability of repayment increase.
Cheap option
Debt with a low interest rate and a low probability of repayment is usually a reasonable trade. It is unlikely to matter, and correcting it later will not be significantly more expensive.
Calculated gamble
Debt with a high interest rate but a low probability of repayment is more difficult. The shortcut could become expensive, but only if the feature succeeds or certain requirements appear. This can be a rational bet for an experiment, as long as we keep watching the assumptions behind it. Closely monitor those decisions to react as quickly as possible.
Manageable debt
Debt with a low interest rate but a high probability of repayment will probably need to be addressed. However, waiting does not make it much more expensive. We should make it visible and schedule repayment when it becomes worthwhile.
Dangerous debt
Debt with both a high interest rate and a high probability of repayment is the dangerous kind. It affects an area that will almost certainly continue to evolve, while every new feature makes the eventual correction more expensive. Taking on this kind of debt should require an exceptional short-term benefit and an explicit repayment plan.
Debt also has running costs
So far, we have treated repayment as a single future event. In reality, technical debt can also produce continuous interest.
A shortcut might make every future change take longer. It might cause regular production incidents, require manual intervention, or make developers afraid to touch part of the system. We pay this cost repeatedly, even if we never formally repay the debt.
That is why technical debt should not only be measured by the effort required to remove it. We should also ask:
- How often will we work in the affected area?
- How much slower will each change become?
- Can the debt cause security, reliability, or compliance problems?
- Is the debt isolated, or will other parts of the system start depending on it?
- Will we notice when the assumptions behind our decision change?
A useful way to summarize the idea is:
Expected cost = probability of repayment × repayment cost + accumulated interest
This does not have to be a precise calculation. Its purpose is to make the trade-off explicit and improve the conversation around it.
Taking on debt deliberately
The conclusion should not be that technical debt does not matter. The conclusion should be that condemning it categorically prevents us from making rational trade-offs.
When consciously taking on technical debt, I find five questions useful:
- What do we gain today?
- What exactly would repayment involve?
- How does the repayment cost grow over time?
- How likely are we to need the affected code in the future?
- What signal will tell us that it is time to repay?
Writing down the answers does not need to involve a lengthy process. A comment in an architectural decision record or a ticket linked to the relevant context may be enough. The important part is that the shortcut remains a conscious decision rather than slowly turning into an unexplained constraint.
We should also consider reversibility. Debt in an isolated UI component is different from debt in authentication, billing, or the core data model. Some decisions are cheap to reverse, while others spread through the entire system. The harder a decision is to reverse, the more careful we should be before accepting it.
Reducing the cost of accidental debt
Now that we have explored deliberate technical debt, we can return to the first reason from earlier: Sometimes we simply do not know that a decision will negatively affect future development. The result is not entirely up to luck. We cannot predict every consequence of a technical decision, but we can influence how costly an unforeseen mistake becomes.
Engineering practices such as automated tests, modular architecture, clear boundaries, code reviews, observability, and regular refactoring make a system more resilient to decisions that turn out to be wrong. They do not prevent accidental technical debt, but they can reduce its interest rate and limit its blast radius. A mistake hidden behind a well-defined interface is usually easier to correct than one that has spread throughout the entire codebase.
This is another reason why good engineering practices matter even when their immediate business value is difficult to quantify: They give us options when our assumptions turn out to be wrong.
Conclusion
Technical debt is neither good nor bad by definition. Like financial debt, it allows us to use future resources to achieve something today. That can help us validate an idea, enter a market earlier, or focus limited engineering capacity on the most important problem.
But debt is only a useful tool if we understand its conditions. We need to know what we gain, what interest we are paying, how likely repayment is, and whether the cost can grow beyond our control.
The goal of good engineering is therefore not to avoid technical debt completely. It is to take on the right debt, for the right reason, under conditions we can afford.
)
)
)
)
)
)
)
)
)
)