Technical debt
A Socratic walk-through of technical debt — reasoned out one step at a time, not lectured.
The question we started with
THE QUESTION #Why does a shortcut that saves a day cost more every week it survives?
A team takes a shortcut to hit a date. They know it is a shortcut; they say so out loud. The saving is one day. Nobody objects, because one day of borrowed time against a real deadline is a trade any sensible person would take.
Six months later the same shortcut is being blamed for a week of lost work. Nothing about it changed — it is the same forty lines it always was. So where did the extra cost come from? Either the team misjudged the original price, or the price is not a fixed quantity at all. It is worth being precise about which.
Reasoning it through
REASONING #Start with what the shortcut actually was. Not a bug — a bug is wrong behaviour. This is code that works. What it lacks is some property that would have made it easy to live with: a clear name, a boundary, a place where the special case is handled once instead of three times. Call that the missing structure.
Now ask the crucial question. Who pays for the missing structure, and when? Not the person who wrote it — they have already banked the day. The payer is the next person who has to change something near it. They must reconstruct the reasoning that a clear structure would have carried for them.
So the cost is not a lump sum sitting in the code. It is a small tax levied per encounter. And that immediately tells you what governs the total: how often the code is encountered, over how long. A shortcut in a file nobody touches again costs almost nothing, forever. The same shortcut on a hot path that every feature crosses is charged weekly.
But per-encounter tax alone gives you a cost that grows linearly, and the question said the cost grows every week. Where does the extra come from? Two mechanisms, and they are worth keeping distinct because people run them together.
The first is that the shortcut shapes what is built on top of it. If a special case has no proper home, the next feature must handle it too, in its own way. Now two places encode the same assumption. The debt has not merely persisted; it has reproduced. This is the genuinely compounding part, and it is compounding in the same sense as interest: the new work is proportional to the size of the existing mess, so the mess grows in proportion to itself.
The second is subtler. The people who knew why the shortcut was taken forget, or leave. What began as a known, bounded compromise becomes unexplained code. Nobody can now tell whether the odd behaviour is deliberate or accidental, so nobody dares remove it, and it must be preserved by everything that comes near. The debt has been converted from a liability into a constraint. Notice that this cost arises purely from the passage of time, with nobody touching anything.
Is the metaphor exact? Not entirely, and this matters. Ward Cunningham, who coined the term in 1992, meant something narrower and more respectable than the way it is used now: shipping code that reflects your current, incomplete understanding of the problem, then refactoring as understanding improves. Sloppiness was never the point. The word "debt" has since been stretched to cover ordinary mess, which flatters the mess — real debt is deliberate, and the deliberateness is what makes it a decision rather than a failure.
There is also no interest rate you can look up. Nobody can tell you that a given shortcut compounds at four percent a week. What we have is a mechanism — more places encoding the same assumption, less remaining explanation — and a direction. Quantified estimates of a codebase's "total debt" produced by static analysis tools should be read as rough indicators, not as figures on a balance sheet.
The analogy
THE ANALOGY #Think of a footpath worn across a lawn because it saves thirty seconds. The first crossing costs nothing and saves real time. But each crossing kills a little more grass, and the barer the strip becomes, the more obvious a route it looks, so more people take it. The path widens because it is a path. Restoring the lawn a year later is not thirty seconds of work — it is reseeding, fencing, and persuading everybody to walk the long way round while it recovers.
The lawn heals on its own if traffic stops, whereas a codebase never quietly repairs itself — neglected code stays exactly as bad as it was, and only deliberate work removes the shortcut.
Clarifying the model
THE MODEL #Two corrections follow from this, both of which change how the trade is made.
First, "we will fix it later" understates the price in a specific way: later, you are not removing the original shortcut, you are removing it plus everything that grew around it. That is not procrastination on a fixed bill; it is choosing a larger bill. The right time to be honest about this is when the shortcut is taken, not when it is discovered.
Second, and pulling the other way: not all debt should be repaid. If the cost is a per-encounter tax, then code that is never encountered accrues nothing, and code that is about to be deleted accrues nothing worth collecting. A team that services all its debt uniformly is paying down loans on assets it has already sold. The useful question is never "is this bad code" but "how often is it crossed, and for how much longer."
Which is why the most valuable habit here is neither purity nor pragmatism but bookkeeping: write down that a shortcut was taken, why, and what would trigger repaying it. That single act blocks the second compounding mechanism — the shortcut cannot become unexplained code if the explanation is written next to it.
A picture of it
THE PICTURE #How to readRead left to right: the bar at week zero is the day the shortcut originally saved, and each later bar is what it would then cost to undo, once other code has been built on the same assumption. The curve is illustrative rather than measured — no real project has a published interest rate — but the shape is the point: the gap between the first bar and the last is the cost of deferral, not of the shortcut itself.
What became clearer
WHAT CLEARED #Technical debt is not a fixed lump of badness sitting in a file. It is a per-encounter tax whose base grows, because unstructured code shapes the code written next to it and because the explanation for it decays with time. That gives a sharper decision rule than "avoid shortcuts": take them deliberately, on code you can name, and write down the reason — since the reason expiring is half of what makes the bill grow.
Where to go next
ONWARD #- Cunningham's original 1992 framing, and how it differs from the term's common use.
- The "debt quadrant" distinction between deliberate and inadvertent, prudent and reckless debt.
- Why architectural debt behaves differently from local code debt — and is far harder to repay incrementally.
Key terms
TERMS #| Term | What it means |
|---|---|
| Technical debt | the future cost of choosing an expedient implementation over a better-structured one. |
| Refactoring | changing a program's internal structure without changing its external behaviour. |
| Coupling | the degree to which one part of a system cannot be changed without changing others. |
Every term the collection defines is gathered in the glossary.