All Insights
essays· 13 min read

Technical Debt Isn't Real

A provocative reframing of our industry's favorite metaphor

SV
Sri VardhanDecember 15, 2023
Share on Twitter
Share on LinkedIn
Copy link

The debt metaphor has outlived its usefulness. Here's why I think we need a new framework for thinking about software entropy and decision consequences.

I want to say something annoying. Technical debt is not real. The metaphor has been useful for thirty years, and it is now actively making our work worse. We should retire it, or at minimum stop talking about it like it is the most important concept in our field.

This is not a rhetorical trick. I genuinely think our reliance on the debt metaphor causes specific, identifiable harm. Let me show you what I mean.

What the metaphor was supposed to do

Ward Cunningham introduced technical debt as a way to communicate with non-technical stakeholders. The point was: shipping a quick implementation has a real cost, and that cost has interest. You can choose to pay the principal down, or you can keep paying interest forever. Smart, simple, useful.

The problem is what happened to the metaphor afterward. It got abstracted into a generic complaint about any code we do not like. It got used to justify rewrites. It got used to dodge accountability. It got used as a shield against any unfamiliar system.

When I hear an engineer say "this codebase has a lot of tech debt," I no longer learn anything. The phrase has become noise.

Three reasons the metaphor breaks

Debt has a known principal

Real debt has a number. You can look up the balance, the interest rate, and the payoff schedule. Technical debt almost never has any of those. We say this module needs a rewrite the way we say the kitchen is messy. It is a vibe, not a balance sheet.

This matters because the moment you try to prioritize, the metaphor stops helping. Which debt is highest interest? Which is the largest principal? Nobody knows. So tech debt budgets become whatever the loudest engineer wants to refactor that quarter.

Not all bad code is debt

Some code is bad because the people who wrote it understood the problem worse than we do now. That is not debt. That is learning made visible. The right move is sometimes to leave it alone. Rewriting it just shifts the unknowns to a new place.

Some code is bad because the requirements changed. That is not debt either. That is drift, and it has a different fix. You do not pay it down, you redesign around the new shape of the problem.

Some code is bad because the original author did not care. That is not debt. That is negligence, and pretending it is debt lets the negligent author off the hook by reframing it as a normal part of engineering.

Calling all of these tech debt papers over the actual diagnosis. And the diagnosis is what determines the cure.

Debt language hides decisions

This is the part that bothers me most. When we say we took on tech debt to ship the launch, we are usually describing a decision someone made consciously, with tradeoffs they understood. That decision deserves credit, not euphemism.

The opposite happens too. When we say this is just legacy tech debt, we are often dodging the fact that nobody made a decision, the system just drifted. That deserves an honest "we let this happen," not a financial metaphor.

In both cases the debt language smooths over the human story, and the human story is where the lesson lives.

What I use instead

I have stopped saying tech debt in my own work. From teams I have worked with, the conversations get sharper when you replace the phrase with something more specific.

A few alternatives:

  • Decision residue. When we say A and would now choose B, the difference is residue. Specific, removable, attributable.
  • Drift. When the system and the world have moved apart over time without any single bad decision.
  • Negligence. When someone did the cheap thing on purpose and did not flag it.
  • Misunderstanding. When the original model of the problem was wrong, and the code reflects that wrongness.

For each of these, the right response is different. Residue gets refactored. Drift gets redesigned. Negligence gets a process change. Misunderstanding gets a rewrite, and only then.

You will notice none of these are "pay down debt over the next sprint."

Why this matters in practice

If you are leading an architecture review, the metaphor you use shapes what gets fixed. Teams that talk in tech debt language tend to run quarterly cleanup sprints that nobody can measure. Teams that name the actual problem tend to fix it once and move on.

The other consequence is on prioritization. "We have tech debt" is never going to win against "we have a feature deadline." It is too vague to be urgent. "Our payments code has decision residue from when we only supported one currency" is a much harder thing for a product manager to deprioritize, because it points at a specific risk.

So what do we do

I am not asking you to ban the phrase. It is too embedded. But I would ask you to do one thing: every time you are about to use it, try to say what you actually mean instead. What kind of bad is this code, and who decided that.

It is a small reframe. In my experience, it changes the conversation more than any process I have introduced.

If you want a deeper read on how this plays out in real systems, the insights section has more on the concepts that, in my view, do most of the work the debt metaphor was trying to do.

References

Tagged

#engineering#metaphors#decision-making
SV

Sri Vardhan

Independent technology studio of one. I help founders and small teams ship serious software without the consultancy overhead. More about me.

Want to discuss this topic?

I am always happy to dig deeper. If a piece sparked an idea or a disagreement, send it over. I read every message myself.

Get in Touch