The term “technical debt” was coined by Ward Cunningham specifically as a financial metaphor. Debt isn’t inherently bad — it’s a tradeoff: you get something now in exchange for a future obligation. When the metaphor is understood, the management of technical debt becomes clearer. When the moral framing replaces the financial one, it becomes a guilt-driven cycle that helps nobody.

The Financial Metaphor, Taken Seriously

Financial debt has a principal (the amount borrowed) and interest (the ongoing cost of carrying it). Technical debt works the same way:

  • Principal: the cost to fully eliminate the debt (rewrite the component, fix the architecture, add the missing tests)
  • Interest: the ongoing tax on every feature or bug fix that touches the debt — extra time, extra complexity, extra risk

Debt makes sense when the return on the borrowed capital exceeds the interest cost. A startup that ships a working product with some architectural shortcuts, raises funding, and later cleans up the architecture has used debt correctly — the principal was smaller than the value captured. A team that ships a prototype to meet a deadline and never revisits it has incurred debt with an interest rate that compounds indefinitely.

The question is never “do we have debt?” (you always do). The question is “is the interest rate on this debt acceptable given what we got for it?”

Classifying Debt by Interest Rate

Not all debt is created equal. Some debt has negligible interest:

Low-interest debt:
  ├── Dead code that isn't touched (costs storage, negligible dev overhead)
  ├── Non-idiomatic code in a stable, well-tested module
  ├── An underpowered data model for a low-traffic feature
  └── Missing documentation in a rarely-changed component

High-interest debt:
  ├── Architectural coupling in the hot path (every feature requires touching it)
  ├── Missing tests in frequently-changed code (regressions accumulate)
  ├── Complex shared mutable state (concurrent bugs, hard to reason about)
  ├── Incorrect data model at the core domain (everything built on a flawed foundation)
  └── Security vulnerabilities (catastrophic when they compound)

Prioritise by interest rate, not by age or visibility. Old code that nobody changes is low interest regardless of how ugly it is. New code in the critical path that everyone touches daily has high interest even if it’s well-written — because being “well-written for now” doesn’t mean it’s right for what the system became.

Debt Visibility: The Balance Sheet Problem

The accounting metaphor breaks down in one important way: technical debt is off the balance sheet. It doesn’t appear anywhere in the company’s financial statements. The engineering team knows it exists; the leadership team often doesn’t, or knows only in the abstract.

This invisibility has consequences. When the engineering team says “we need a quarter to pay down debt,” it sounds like cost without benefit. When the same problem is framed as “we’re currently paying 30% overhead on every feature in the payments module due to the coupling introduced in Q1, and here’s what reducing it to 5% is worth in feature velocity,” it’s a business decision with quantifiable return.

Making debt visible requires translating from engineering language to business language:

Engineering descriptionBusiness translation
“The auth system is a mess”“Every auth-related feature takes 3x longer than it should and has a 40% regression rate”
“We need to refactor the data model”“We can’t build the analytics feature product wants until we fix the data model; estimated 6-week unlock”
“Our tests are slow and flaky”“CI takes 45 minutes, blocking 8 engineers who each deploy 3x/day — 18 hours of blocked dev time daily”
“This code has no documentation”“Each new engineer takes 3 extra weeks to become productive on this module”

The translation is effort. It requires actually measuring the interest rate — tracking how long features take in high-debt areas vs low-debt areas, how many regressions come from specific modules, how long onboarding takes. Engineering teams that measure these things have the ammunition to make the case for debt reduction as an investment rather than a request for indulgence.

Deliberate vs Inadvertent Debt

Martin Fowler’s debt quadrant distinguishes between:

                    RECKLESS              PRUDENT
                ┌──────────────────┬──────────────────┐
                │                  │                  │
DELIBERATE      │ "We don't have   │ "We must ship    │
                │ time for design" │ now and deal     │
                │                  │ with consequences"│
                ├──────────────────┼──────────────────┤
                │                  │                  │
INADVERTENT     │ "What's          │ "Now we know     │
                │ layering?"       │ how we should    │
                │                  │ have done it"    │
INADVERTENT     └──────────────────┴──────────────────┘

Deliberate-prudent debt is the legitimate use of the mechanism — you make a conscious tradeoff, know what you’re incurring, and plan to address it. Startups live here intentionally.

Inadvertent debt is the dangerous kind — you didn’t know you were incurring it. This happens when engineers don’t have enough context to make good decisions (new domain, new technology, new scale), when the system evolves past the design that was appropriate for its original scale, or when shortcuts are made without anyone noticing the long-term cost.

Deliberate-reckless debt is what erodes engineering culture — “we’ll fix it later” said without intention to fix it, shortcuts taken when there was time to do it properly. This is the moral failure the guilt-driven framing correctly identifies, but conflating all debt with this category causes good deliberate-prudent decisions to be treated as shameful.

The Repayment Strategy

The practices that actually work for managing debt over time:

The Boy Scout Rule applied at the margin. Leave code slightly better than you found it — fix the obvious bad variable name, add the missing test case for the bug you fixed, extract the duplicated logic into a function while you’re in the file. Applied consistently, this prevents debt from compounding without requiring dedicated repayment sprints.

Dedicated capacity, not heroics. “20% time for technical work” is meaningless without tracking what gets done in it. Named debt items, with owners and target completion dates, treated like any other work item. The alternative — “engineers fix debt in their spare time” — means it never happens.

Retire debt before it occludes new work. The forcing function for repayment is often: “we can’t ship feature X without fixing Y first.” This is too late. By this point the debt is blocking revenue and the timeline is now pressured. Identify the high-interest debt before it reaches criticality.

Don’t accrue debt you can’t repay. The most dangerous debt is the kind you incur in a component that will be too critical to touch by the time you’d want to fix it. The core data model, the auth system, the event sourcing schema — these are the places where “we’ll clean it up later” should trigger the most skepticism.

The goal is not zero debt — that’s perfection in an imperfect world with real deadlines. The goal is a known, managed debt load with an acceptable interest rate, decreasing over time in the high-interest areas that matter most.