Technical Debt Is About Interest, Not Ugly Code
Ward Cunningham coined the metaphor in 1992 and meant something precise: ship code that reflects your current, partial understanding, then rewrite it once you understand better. He never meant careless code. The difference decides whether your refactoring budget gets approved.

Key takeaways
- Ward Cunningham coined the technical debt metaphor in his 1992 OOPSLA experience report on the WyCash Portfolio Management System, where he wrote that "shipping first time code is like going into debt" and that "every minute spent on not-quite-right code counts as interest on that debt."
- Cunningham’s debt was shipping code that reflects your current, incomplete understanding of a problem in order to learn faster, then rewriting it once you understand better. He explicitly said he was never in favor of writing code poorly, so careless code was never what the metaphor described.
- The test for whether something is technical debt is whether it charges interest, meaning whether it makes the next change to that area slower. Code that is ugly but never touched again charges nothing and is not debt.
- Martin Fowler published the technical debt quadrant on October 14, 2009, splitting debt along two axes, deliberate versus inadvertent and prudent versus reckless, which produces four kinds of debt that each need a different response.
- Two of the four DORA keys make interest visible in a budget conversation: change lead time is the time from a commit reaching version control to being deployed in production, and change fail rate is the ratio of deployments that require immediate intervention. Scoped to the affected directory, they turn a taste argument into a delivery number.
Almost every engineering team keeps a technical debt list. Almost none of them are looking at technical debt. What they have is a list of code somebody dislikes, which is a completely different object, and the confusion between the two is the reason the refactoring budget never gets approved.
The term has a precise origin, and the origin turns out to be far more useful than anything the industry built on top of it. Ward Cunningham coined it in 1992, in a short experience report at OOPSLA about the WyCash Portfolio Management System, a bond portfolio tool his team was building in Smalltalk.[1] He was not writing a manifesto. He was explaining to a room of object-oriented programmers why his team kept rewriting parts of a shipping product and why that was a feature rather than an embarrassment.
What Cunningham actually wrote
Here is the whole thing, from the 1992 report:
“Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. Objects make the cost of this transaction tolerable. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object-oriented or otherwise.”[1]
Read it for what it does not say. It does not say write sloppy code. It does not say skip tests. It does not say cut corners under deadline pressure. The debt is shipping first time code, code written before you fully understand the problem, in order to get the product in front of reality sooner and learn what the problem actually is. The interest is the time you lose working against a structure that encodes an understanding you have since outgrown.
Cunningham got asked about this often enough that in 2009 he recorded a short video to correct the drift. His words there are blunt. If you want to go into debt by developing software you do not completely understand, he says, “you're wise to make that software reflect your understanding as best you can.”[2] And the failure mode he describes is not messiness at all:
“If you develop a program for a long period of time by only adding features but never reorganizing it to reflect your understanding of those features, then eventually that program simply does not contain any understanding and all efforts to work on it take longer and longer.”[2,3]
Plain English
How one metaphor drifted
From a Smalltalk experience report to a catch-all excuse
- 1992
Cunningham coins it at OOPSLA
In the WyCash experience report, debt is a deliberate, short-horizon trade: ship code reflecting partial understanding, then consolidate it with a rewrite. Interest is the time lost to not-quite-right code.[1]
- Oct 14, 2009
Fowler publishes the quadrant
Martin Fowler splits debt along two axes, deliberate versus inadvertent and prudent versus reckless. It is the first widely used framework that admits not all debt arrives the same way or deserves the same response.[4]
- 2009
Cunningham records a correction
He restates that he is not endorsing poor code, only code that honestly reflects current understanding, and that the metaphor only works if the code stays clean enough to refactor later.[2]
- Today
The term means everything and therefore nothing
“Technical debt” now covers a legacy framework, a disliked naming convention, an outage nobody fixed, and a library two majors behind. Four different problems, four different remedies, one word that hides the difference.
Takeaway
The 1992 definition survives a stress test that the modern usage does not: it tells you what you borrowed, what you owe, and when you are in trouble. A word that covers everything on a backlog cannot do any of that.
The interest test
Here is the part that makes the metaphor operationally useful, and it is the part that gets skipped. Debt is only debt if it charges interest. Not metaphorically. Structurally. A loan with a zero percent rate that nobody ever calls in is not a financial problem, and code that is ugly but never touched again is not an engineering one.
So the test is one question: does it make the next change to this area slower? If yes, you can measure the interest, price it, and argue about whether refinancing is worth it. If no, you have found something you dislike, which is fine, but disliking code is not a business case.
One question, three answers
Sorting a backlog into debt, defects, and taste
What lands on the list
- A module everyone avoidsNobody wants to open it.
- A data model that predates the second customer typeEvery new feature needs a special case.
- An old framework versionStill supported, still working.
- Naming and formatting nobody likesFrozen code, no roadmap items near it.
Does it make the next change slower?
The interest test. Answer it with a real upcoming change, not a hypothetical one.
Real debt, so price it
- The data modelEvery roadmap item pays a tax. Interest is measurable in days per feature.
- The avoided moduleOnly if the roadmap points at it. Otherwise it moves to the right.
The same sorting question applied to four typical backlog entries.
Takeaway
Run this against your own list and be honest about the answers. In my experience most of what gets filed as technical debt fails the interest test outright, and the few items that pass are usually structural, not cosmetic. That ratio is the whole problem. If nine of ten items on the list cost the business nothing, no wonder nobody funds the tenth.
Fowler's quadrant, and why it matters for the conversation
On October 14, 2009, Martin Fowler published the technical debt quadrant, which sorts debt on two axes: was it deliberate or inadvertent, and was it prudent or reckless.[4] The four cells are worth naming, because each one implies a different fix.
- Deliberate and prudent: “We must ship now and deal with the consequences.” This is Cunningham's debt, and it is the only kind you would ever choose on purpose.
- Deliberate and reckless: “We don't have time for design.” A decision, but a bad one. The fix is a process fix, not a code fix.
- Inadvertent and reckless: “What's layering?” Nobody decided anything. The fix is hiring, training, or review, and refactoring alone will regenerate the same problem in six months.
- Inadvertent and prudent: “Now we know how we should have done it.” Fowler calls this inevitable even for excellent teams, and he is right. You cannot prevent it. You can only budget for it.
The quadrant earns its place because it kills the moralizing. Two of the four cells involve no bad judgment at all, and one of them is unavoidable by construction. When a team lumps all four into one list titled “tech debt” and takes it to a planning meeting, the implicit message an executive hears is “we made mistakes and now we want time to fix them.” That framing loses every time it competes with a revenue feature.
“Most of what teams call technical debt is not debt. It is code they dislike. Putting the two in one list is why the real debt never gets funded.”
“We'll fix it later” is not a plan
Cunningham's formulation has a repayment clause built in: a little debt speeds development so long as it is paid back promptly with a rewrite.[1] Drop that clause and the metaphor stops describing debt and starts describing a default.
A real intention to pay has three parts: a trigger condition, an owner, and a stated interest rate. Without a trigger, “later” is never, because there is no moment at which anyone is obliged to act. I have had good luck writing this straight into the code, next to the thing it describes, where it is impossible to lose:
// DEBT (deliberate, prudent): the export path assumes one tenant per account.
// Why: we shipped this before the enterprise plan existed and had one customer.
// Interest: every new report type needs a hand-written tenant filter, ~1 day each,
// plus one production incident so far (INC-412) from a filter that was forgotten.
// Trigger: the second enterprise tenant signs, or 2026-12-01, whichever comes first.
// Owner: payments team. Estimated payoff: 5 days.
export function buildExport(accountId: string) {
// ...
}Four lines of comment, and the item now has everything a planning conversation needs. Note that the interest line is the load-bearing one. “One day per report type plus one incident” is a number somebody can multiply by the number of report types on next quarter's roadmap. “This is hacky” is not.
The same discipline applies to the debt that has its own dedicated ledger. A flag left on after its rollout finished is textbook deliberate debt with no trigger attached, which is exactly the argument in why a feature flag is a production change that skips your deploy pipeline. And the largest version of this decision, whether to pay down architectural debt by splitting a system apart, deserves its own analysis rather than a reflex, which is what deciding between a monolith and microservices works through.
Making the interest visible to people who hold the budget
Engineers describe debt in nouns: the module, the schema, the framework. Budget holders buy verbs and numbers: this is slower, by this much, costing this. The translation layer is delivery metrics, scoped to the affected area rather than the whole codebase.
Two of the four DORA keys do most of the work here. Change lead time is defined as the amount of time it takes for a change to go from committed to version control to deployed in production.[5] Change fail rate is the ratio of deployments that require immediate intervention following a deployment.[5] Both are directly sensitive to the thing you are claiming: if a subsystem really is charging interest, work that touches it takes longer to get out and breaks more often when it does.
Three artifacts, in order of how convincing they are:
- Change lead time, filtered to the affected paths, against the repository baseline. If pull requests touching that directory take three times as long to reach production as everything else, you are not describing taste, you are describing a measured slowdown.
- Change fail rate for deployments touching that area. A subsystem that produces a disproportionate share of the rollbacks and hotfixes has a defect cost attached to it, and defect cost is a language finance already speaks.
- Two or three named tickets that ran three times over estimate, with the specific reason. Not a chart. A story with an identifier on it. Charts get argued with; “this took nine days and here is the commit where we found out why” does not.
One caution before you go build a dashboard out of this. Metrics borrowed to win an argument have a habit of becoming targets, and a lead time number that the team is now judged on will improve without anything underneath it improving. That failure mode has its own catalog, in the ways engineering metrics get gamed. Use these numbers to size one decision, then put them down.
The honest case for never paying some of it back
Here is where I part company with most writing on this subject. A lot of technical debt should be carried to the grave, deliberately, and saying so out loud is what makes the rest of your argument credible.
The math is not complicated. Paying down debt costs principal, which is engineering time you could have spent on something else. It returns avoided interest, which is future time saved on future changes. If the area is stable, if the roadmap does not point at it, if the service is being decommissioned in eighteen months, then the avoided interest is near zero and the principal is real. Paying it is a straight loss dressed up as professionalism.
The same logic scales up. A modernization program that touches everything, rather than the two systems the roadmap actually runs through, is a very expensive way to pay off loans nobody was calling in, which is why sequencing a platform modernization is mostly an exercise in deciding what to leave alone.
Heads up
What I would actually do on Monday
Take your technical debt list and run every item through the interest test. Anything that fails it moves to a separate document, call it “code we would write differently,” and stop bringing it to planning. Anything that passes gets three additional fields: what it costs per change, what triggers the payoff, and who owns it. Whatever survives that filter is short, specific, and priced, and a short specific priced list is a thing an executive can say yes to.
The reason this works is not that it is a clever framing. It is that it is the original meaning. Cunningham gave the industry a financial metaphor with a repayment clause and an interest rate in it, and the industry kept the word and threw away both of the things that made it operate. Thirty-four years on, the fix is not a new framework. It is reading the 1992 paragraph again and asking, of each item on the list, what exactly you borrowed and what exactly you are paying.
Sources and further reading
- 1.PrimaryWard Cunningham, "The WyCash Portfolio Management System," OOPSLA ’92 experience report. The original coinage. Source of the "shipping first time code is like going into debt" passage and the "every minute spent on not-quite-right code counts as interest" line.
- 2.PrimaryWard Cunningham, "Debt Metaphor" (2009 video), transcript. Cunningham’s own correction of the metaphor: he is not endorsing poor code, only code that reflects current understanding, and the metaphor only works if the code stays clean enough to refactor.
- 3.ReportingDave Rupert, "Technical debt as a lack of understanding". Quotes the passage from the 2009 video about a program that only ever gains features and eventually "does not contain any understanding."
- 4.PrimaryMartin Fowler, "Technical Debt Quadrant". Published October 14, 2009. The deliberate/inadvertent and prudent/reckless axes, the four cells, and the argument that inadvertent prudent debt is inevitable even for good teams.
- 5.PrimaryDORA, "DORA’s software delivery metrics: the four keys". Definitions used here: change lead time as the time from a change being committed to version control to being deployed in production, and change fail rate as the ratio of deployments that require immediate intervention.
Frequently asked questions
- What is technical debt?
- Technical debt is code that made sense given what you knew at the time and now costs you time on every change until you rewrite it. Ward Cunningham coined the term in 1992 to describe shipping software that reflects your current, partial understanding of a problem so you can learn faster, on the condition that you go back and consolidate once your understanding improves. The cost of not going back is the interest.
- Is bad code the same thing as technical debt?
- No. Bad code is a quality problem; technical debt is a deliberate trade of future time for present speed. Cunningham said plainly that he was never in favor of writing code poorly, only in favor of writing code that reflects your current understanding even when that understanding is partial. Careless code written by someone who did not know better is closer to what Martin Fowler calls inadvertent reckless debt, and it is real, but it is not what the original metaphor described.
- How do you know if something is really technical debt?
- Ask whether it makes the next change to that area slower. Debt is only debt if it charges interest, so if a module is ugly, badly named and thoroughly disliked but nobody has touched it in two years and nobody plans to, it charges nothing and paying it down buys you nothing. If a change that should take an afternoon reliably takes three days because of how something is structured, that is interest, and you can price it.
- What is Martin Fowler’s technical debt quadrant?
- It is a two-by-two published on October 14, 2009 that sorts debt by whether it was deliberate or inadvertent and whether it was prudent or reckless. Deliberate prudent debt is the considered decision to ship now and deal with the consequences. Deliberate reckless is skipping design because there is no time. Inadvertent reckless is a team that does not know what layering is. Inadvertent prudent is the good team that only learns the right design after a year of building the wrong one, which Fowler calls inevitable.
- How do you get budget to pay down technical debt?
- Stop describing the code and start pricing the interest, using delivery numbers scoped to the affected area. Show the change lead time for work touching that directory against the rest of the codebase, the change fail rate for deployments that touch it, and the two or three specific tickets that took three times their estimate and why. A finance-literate executive will fund a measured slowdown. Nobody funds "the code is messy."
Written by
Tech Talk News Editorial
Computer engineering background. Writes about software, AI, markets, and real estate, and the places where the three meet.
More about the author