Skip to content

Technical Debt, Precisely

“Technical debt” is the most used and least precise term in the profession. It covers deliberate trade-offs, accumulated mess, obsolete dependencies, and work somebody simply did badly — which makes it useless for deciding anything, because those four need completely different responses.

Precision here is not pedantry. The classification determines the response, and a backlog of undifferentiated “debt” is a backlog nobody can prioritise.

Martin Fowler’s framing, from his note on the technical debt quadrant, crosses two axes: was the decision deliberate or inadvertent, and was it prudent or reckless. Four cells, four different responses.

Prudent Reckless
Deliberate “We must ship now and will deal with the consequences” “We don’t have time for design”
Inadvertent “Now we know how we should have done it” “What’s layering?”

Deliberate and prudent is the only cell that is genuinely debt in the useful sense. A conscious trade: speed now, cost later, with both sides understood. The response is to record it, with the repayment condition — which is a decision record, and Module 9’s reversal-condition field is exactly the right shape for it.

Deliberate and reckless is not a trade; it is a choice to skip work with no accounting of the cost. The response is a process question rather than a technical one, because the same decision will be made again next quarter unless something changes.

Inadvertent and prudent is the healthiest cell and the one most often mislabelled. The team did competent work, learned something, and now knows better. That is not a failure — it is what learning looks like in a codebase, and the response is ordinary refactoring as the area is touched.

Inadvertent and reckless is not debt at all. It is work done without the knowledge to do it adequately, and the next topic argues that calling it debt actively launders it.

graph TD
  A["<b>Deliberate + prudent</b><br/>a real trade<br/><i>record it with a<br/>repayment condition</i>"] --> E["Four cells,<br/><b>four responses</b>"]
  B["<b>Deliberate + reckless</b><br/>no accounting<br/><i>a process problem</i>"] --> E
  C["<b>Inadvertent + prudent</b><br/>learning<br/><i>refactor as you touch it</i>"] --> E
  D["<b>Inadvertent + reckless</b><br/>not debt at all<br/><i>a capability problem</i>"] --> E

  classDef good fill:#7D9A4E,stroke:#5F7A38,stroke-width:2px,color:#ffffff
  classDef mid fill:#E8A33D,stroke:#C4832A,stroke-width:2px,color:#ffffff
  classDef bad fill:#D9695B,stroke:#B4483A,stroke-width:2px,color:#ffffff
  classDef hub fill:#5B8FB9,stroke:#4A7A9E,stroke-width:2px,color:#ffffff
  class A,C good
  class B mid
  class D bad
  class E hub

The same code can sit in any of these cells. What differs is how it got there, and that history is what determines the correct response.

The metaphor is useful for one purpose — explaining to non-engineers that speed now costs later — and misleading for almost everything else.

There is no fixed interest rate. The cost of a shortcut depends entirely on whether anyone touches that code again. A shortcut in a module nobody opens for three years costs nothing; the same shortcut in the hottest path in the system compounds weekly. So the carrying cost is a function of change frequency, which means prioritising debt by severity is wrong and prioritising it by where change is happening is right.

There is no principal you can look up. You cannot know what full repayment costs until you attempt it, and estimates are reliably low because the entanglement is what was hidden.

Partial repayment sometimes achieves nothing. Half-repaying a loan halves the interest. Half-migrating a data model can leave you maintaining two models with translation between them — strictly worse than either end state. Some repayments are only valuable completed, and that changes how they must be sequenced.

And you can be forgiven the whole balance. If the system is retired, the debt evaporates. Which makes “is this area being retired?” the first question to ask about any proposed repayment, and the reason the previous topic’s trajectory arithmetic matters so much here.

The practical discipline: structural work goes in the same backlog as features, estimated the same way, and prioritised against them.

A separate “tech debt backlog” is a list of things that will never be done, because it competes with the real backlog and loses every time. It also lets the organisation avoid the actual decision, which is how much delivery capacity goes to structural work — a decision that deserves to be made explicitly and defended, rather than handled by a list that quietly never advances.

This is the core of your technical debt assessment, and the rubric requires each item classified by quadrant with the response it implies. A classification with no attached response is a taxonomy exercise.


→ One of the four items has a sharper question attached, and one is not debt at all. — The design payoff line, and debt that is not debt