Skip to content
Advanced11 min readUpdated September 2026

Technical Debt As An Economic Decision

Recovering the original meaning of the metaphor, distinguishing the four kinds of debt, and making the interest payment visible in terms a finance function can act on. Including the cases where not paying it down is the correct answer.

Technical debt is the most successful metaphor in software engineering and the most comprehensively misused. It has become a term of art meaning "code I do not like", deployed in planning conversations as a way of requesting time without stating a benefit, and heard by everyone outside engineering as a euphemism for tidying up.

That is a shame, because the original idea was sharper than what replaced it, and it was specifically designed to make a financial argument. Used properly, it lets an engineering leader present a rework decision in the same terms as any other capital allocation question: here is the liability, here is what it costs us per period to carry it, here is the cost of retiring it, here is the return. Used carelessly, it produces an annual negotiation in which engineering asks for a percentage and the business asks what it will get, and neither side can answer the other.

The fix is not better advocacy. It is restoring the two things the metaphor was built to carry — a distinction between kinds of debt, and a quantified interest payment — and being willing to conclude, sometimes, that the right answer is to keep paying the interest.

What Cunningham actually meant

Ward Cunningham introduced the metaphor to explain to non-technical stakeholders why a team would go back and rework code that already worked. His argument was about understanding, not about quality shortcuts.

You ship a first version reflecting your current understanding of the domain. That understanding is necessarily incomplete, because you learn what the domain really is by building for it and watching what happens. Shipping is how you acquire that learning, and shipping early is correct. But the code you shipped now encodes an outdated model of the world, and every subsequent change made against that outdated model costs a little more than it should. That extra cost is the interest. Refactoring the code to match your improved understanding is the repayment.

Two consequences follow, and both have been lost.

The first is that in the original framing, taking on debt is a deliberate and often excellent decision. Going into debt is how you ship early enough to learn. The metaphor was never a warning against debt; it was an argument for managing it consciously, as a business manages borrowing.

The second is that debt in this sense arises from learning rather than from carelessness. Messy code written badly by someone who knew better was not what the metaphor described — that is defective work, and calling it debt gives it an unearned respectability. The two have different remedies: you repay learning debt by refactoring towards your new model, and you address defective work by changing how work is produced.

Michael Feathers supplied the other half of the practical picture with his working definition of legacy code as code without tests. Whatever the origin of the mess, the reason it is expensive to change is usually that you cannot change it safely — which is why remediation starting with characterisation tests almost always outperforms remediation starting with a rewrite.

The four kinds, and why the distinction pays

Martin Fowler's technical debt quadrant separates debt along two axes: whether it was taken on deliberately or inadvertently, and whether the decision was prudent or reckless. It looks like a taxonomy exercise. It is actually a triage tool, because each quadrant demands a different response from a different person.

QuadrantWhat it looks likeCorrect responseWho owns it
Deliberate and prudentWe know the clean design; we are shipping now to hit a market window and will repay after launchRecord the decision, the trigger for repayment and the expected interest; repay on the triggerProduct and engineering jointly
Deliberate and recklessWe do not have time for design, and never willStop. This is a management failure, not an engineering oneLeadership
Inadvertent and prudentNow that it is built, we understand the right design — which we could not have known beforeRefactor as understanding improves. This is Cunningham's original case and it is healthyThe team, continuously
Inadvertent and recklessWhat is a layering violationCapability gap. Fix through coaching, review standards and hiring, not through a remediation budgetEngineering leadership

The practical value is that it stops one conversation from having to serve four different problems. An organisation with a large inadvertent-and-reckless inventory does not have a debt backlog; it has a capability problem, and funding a remediation programme will produce new debt as fast as it retires the old. An organisation with a lot of deliberate-and-prudent debt and no record of the decisions has a governance problem: the borrowing happened, but nobody wrote down the terms, so nothing will ever trigger repayment.

Most codebases contain all four, and the proportions tell you what kind of intervention is warranted before you spend anything.

Why twenty percent for tech debt fails

The standard remedy is to reserve a fixed share of capacity — twenty percent is the traditional figure — for technical debt. It is well intentioned, it is easy to agree in a steering meeting, and it fails with great consistency. It is worth understanding why, because the failure modes are structural rather than a matter of discipline.

It is a budget without an investment case. A fixed allocation is not tied to any specific expected return, so it cannot be evaluated, defended or increased on evidence. It survives on goodwill, which means it is the first thing cut under pressure — precisely when accumulated debt is making delivery slowest and the case for spending is strongest.

It makes debt a separate category of work. Once remediation is a distinct budget line, engineers stop improving code as part of doing the work and start writing debt tickets for a backlog that will be prioritised against features by someone with no basis for comparison. The opportunistic refactoring that keeps a codebase healthy — leaving each area slightly better than you found it — gets pushed out of normal work and into a queue.

The percentage is unrelated to the actual interest rate. A young codebase might warrant five percent. A twelve-year-old system being extended in a direction it was never designed for might warrant sixty for a period. A single constant across both is guaranteed to be wrong in both, and being wrong in the second case is the expensive direction.

It splits attention rather than finishing anything. Twenty percent of a team's week, distributed across whatever each engineer considers worst, produces many partially improved areas and no completed remediation. Debt reduction has thresholds: a module becomes dramatically cheaper to change only when the last obstacle is removed, not proportionally as you chip at it. A better pattern is full focus on one target until it is done, then the next.

The alternative is not a different percentage. It is treating each significant piece of remediation as an investment with a stated return, competing on the same basis as feature work — which requires you to be able to state the return.

Making the interest visible

Engineering teams describe debt in engineering terms: coupling, duplication, missing tests, a framework three major versions behind. None of these are costs. They are causes. The cost is what the organisation pays because of them, and it shows up in four places that are all measurable with instrumentation you probably already have.

Cycle time, split by area of the codebase. Compare the median and eighty-fifth percentile for changes touching the suspect module against changes elsewhere, using the flow measures you should already be collecting. The difference is the interest payment, denominated in delay, and it is the single most persuasive number available because it is observed rather than estimated.

Change failure rate and time to restore, by area. If changes to one component fail disproportionately, that component is charging you in incidents. Incidents have a cost the finance function already understands and frequently already tracks.

Onboarding time to first meaningful change. How long from a new engineer joining to their first independent production change in that area. This is a direct measure of accidental complexity, and it scales with every hire you plan to make — which is what makes it land with people who are planning headcount growth.

Estimate inflation and abandoned work. Track how often work in a given area overruns significantly, and how often proposed changes are quietly dropped because they are judged too expensive. That second category is the most under-reported cost of debt: the features nobody attempted. A competitor who can attempt them is not paying your interest.

Together these convert "the payments module is awful" into "changes to the payments module take materially longer, fail more often and are increasingly declined". That is a sentence an executive can act on, and it references no engineering concepts at all.

The argument a finance function can act on

A CFO is not hostile to rework. They are hostile to spending without a return, presented by someone who cannot answer follow-up questions. Present the case the way any other investment would be presented.

State the liability in the organisation's own units: this system consumes a given share of engineering capacity in carrying cost, observable in the cycle-time differential and in the incident record. State the trend, because a liability that is growing is more urgent than one that is stable, and debt compounds when new work is built on top of old. State the cost of retirement as a range with the basis for the range, not a point estimate presented with false confidence. State the return as recovered capacity plus avoided incidents plus options you cannot currently exercise, and say which of those you can verify afterwards.

Then state what happens if you do nothing, honestly. Sometimes the honest answer is that the system continues to function and the cost stays flat, which is a real answer and one you should be prepared to give. The credibility you keep by saying so is what makes the next case land.

Two framings help disproportionately. Recovered capacity is a genuine cost avoidance, directly comparable to the cost of the engineers you would otherwise hire. And optionality tends to work with people who allocate capital: debt is not only a running cost, it forecloses moves. The strategic response you cannot make this quarter because the system will not permit it is the expensive part, and it never appears on any engineering report.

When not paying it down is correct

An honest treatment has to include the cases where carrying the debt is the right decision, and there are more of them than most engineers concede.

Code you do not change. Interest is paid per change. A component that has been stable for years, that nobody touches, that is well isolated behind an interface, is charging you nothing regardless of how ugly it is. Refactoring it converts zero cost into real cost plus real risk. Ugliness in a quiet corner is not a liability; it is decoration you dislike.

Systems with a known end date. A platform being decommissioned in a year should be maintained, not improved. The remaining interest payments are bounded and the principal repayment is wasted.

Short-horizon businesses. A company that may not exist in eighteen months is rationally indifferent to eighteen-month payback periods. Startups taking on enormous deliberate debt before product-market fit are frequently correct, provided the decision is conscious and the repayment happens when the fit arrives rather than being indefinitely deferred.

When the constraint is elsewhere. If delivery is limited by a slow approval process or a discovery bottleneck, making the code easier to change buys you nothing. Fix the constraint first. Local optimisation of a non-constraint is the most common way remediation effort disappears without a visible result.

When the real answer is replacement. Sometimes the interest is so high and the principal so large that incremental repayment will never converge. Strangling the system — routing functionality gradually to a replacement while the original continues to run — is a different decision with different economics, and dressing it up as debt remediation to make it easier to fund does nobody any favours.

The discipline is to make each of these an explicit, recorded decision with a review date, rather than a silent default. Debt that nobody decided to carry is the kind that compounds.

What to do on Monday

Produce the cycle-time differential. Take the last six months of changes, tag each by the primary area of the codebase it touched, and compare distributions. You will have your first defensible interest figure by the end of the day, and it will not match where people assumed the problem was.

Take a sample of your debt backlog — thirty items is plenty — and sort it into the four quadrants. The proportions tell you whether you are facing a remediation problem, a governance problem or a capability problem, and those need different money spent by different people.

Then pick one target: the area with the worst cycle-time differential that is also under active change. Write a one-page investment case with a stated cost, a stated expected improvement and a date on which you will report the actual result. Do not ask for a percentage. Ask for a decision on a transaction, and then publish the outcome whichever way it goes.