Interest: Why Debt Compounds
The shortcut is the principal. The interest is that every later change in that area costs more — and because later changes are built on earlier ones, the cost grows rather than staying flat.
The requirement, the obvious build, and why it breaks
Every lesson starts where the work starts: someone asked for something, and the first implementation that comes to mind survives until the requirement changes.
The shortcut cost us a week to take. Why has it cost far more than a week to live with?
Six months after the pricing rule was copied into a second module "just for the report", the team is asked for its fifth pricing change. Each one has taken longer than the last, and nobody can say why.
The shortcut cost a week. If we ever need to fix it, it will cost about a week. Until then it is free.
It is not free while you are carrying it: every change in the affected area pays a surcharge, and those payments are invisible because they are spread across unrelated tickets.
- It is not free while you are carrying it: every change in the affected area pays a surcharge, and those payments are invisible because they are spread across unrelated tickets.
- The principal grows. Each new feature is written against the shortcut, so it does not stay one week of work — it becomes one week plus everything built on top of it (Change Amplification).
- The surcharge grows too. Two copies mean two edits and one comparison; four copies mean four edits and six pairwise comparisons, and the discovery cost of finding them all rises with each addition.
- Because nobody attributes the surcharge to the shortcut, the estimate for each pricing change just quietly rises, and the team is judged for getting slower rather than for carrying a decision someone made.
What limits the solution, and what must never stop being true
This domain leads with these two. A design that ignores its constraints is not a design, and an invariant nobody named is one nothing is protecting.
- The team ships weekly, so every change has to be small enough to review in a day.
- Two of the copies are in modules owned by other teams, so coordination is part of every change.
- Nobody kept a record of what any past pricing change cost, so the trend is asserted rather than known.
- All copies of the rule must agree at all times, and the only thing currently guaranteeing that is care.
- Any repayment must be incremental — no release may require all copies to change at once (Incremental Migration).
Who owns what, and where the seams fall
Responsibilities decide boundaries; boundaries decide what an interface has to say.
- Whoever carries the debt owns making the interest visible — attributing the surcharge to the entry, so the trend is data rather than a feeling (The Debt Register).
- Whoever plans work owns the comparison: the cost of repayment against the accumulated surcharge of not repaying.
- Nobody owns "reduce interest in general". Interest is per-item and per-area, and treating it as a global property is how debt programmes become unfocused (What Technical Debt Actually Is).
- Interest accrues only where change arrives. A shortcut in a module nobody edits accrues nothing, which is why area matters more than severity (When Design Does Not Pay).
- The unit is the change, not the month. Debt in a monthly-changing area is expensive; the same debt in a yearly-changing area is nearly free.
- Draw the boundary of the affected area explicitly, because interest is what makes containment worth paying for at the moment you take the debt (Deliberate Debt).
One rule change, priced at two moments
The clearest way to see compounding is to price the same requirement twice — once shortly after the debt was taken, and once four features later — with nothing else changed. The design did not get worse in between. What changed is how much has been built on it.
Add a promotional discount that applies to the order subtotal before tax. Identical requirement both times.
Two edits, one comparison, an afternoon. Everyone concluded the copy was harmless, and given what was in front of them that conclusion was reasonable.
Five edits, six pairwise comparisons, two other teams, and a day spent deciding which of two divergent rounding behaviours is correct before any code is written. Same requirement, four times the work.
Why the surcharge grows faster than the copies
Two copies are twice the edits and one comparison. Four copies are four times the edits and six comparisons. The edits scale with the number of places; the work of establishing that they still agree scales with the number of *pairs*, and the discovery cost — finding the list at all — scales with how many people have joined since the last time anyone looked.
This is the mechanism behind the vague feeling that a codebase is "getting slower". It is not slower everywhere. It is slower in exactly the areas where a rule has more than one home, and it is slower in proportion to something that grows faster than the thing anyone is counting.
- The row where teams notice is four, and the row where the decision should have been made is two (The Rule of Three).
- A shared corpus test moves you down the last column without changing the first, and costs a day (Contract Tests).
- Adding a consumer is the event that raises the interest rate, and it is never reviewed as such (Shotgun Surgery).
- None of these counts is a quality measure. They describe one rule in one area, which is the only scope at which they mean anything.
| Copies of the rule | Edits per change | Pairwise agreements to check | What actually goes wrong |
|---|---|---|---|
| 1 | 1 | 0 | Nothing. This is the state you are trying to return to. |
| 2 | 2 | 1 | Nothing yet, which is why the second copy always gets approved. |
| 3 | 3 | 3 | One is forgotten occasionally; caught in review about half the time. |
| 4 | 4 | 6 | Drift begins. Nobody holds all four in mind, so a difference survives a release. |
| 5+ | 5+ | 10+ | Discovery dominates: the work is finding the list, not editing it, and the list is never provably complete. |
Repay, cap, or carry
There are three honest responses and the middle one is chronically underused. Capping the interest — stopping the growth without removing the principal — is usually a day of work and buys most of the benefit while you decide whether repayment is worth it.
What does the next year of changes in this area cost under each response?
when The area changes monthly, the repayment is bounded to a week or two, and tests exist.
cost A week of roadmap time and a new coordination point. Pays back around the third change, which is soon enough to argue for.
when You are unsure whether the area keeps changing, or repayment is not yet affordable.
cost A day: a shared corpus test, a lint rule forbidding new copies, a dependency test enforcing containment. Stops the compounding without removing the principal (Contract Tests).
when The area is stable, or the feature is scheduled for replacement within the year.
cost Nothing now, and a register entry with a revisit trigger so the decision is re-made rather than forgotten (Revisit Triggers).
when A funded feature lands in the area anyway.
cost Almost nothing extra — the tests are running and the reviewers are present. The cheapest repayment available and the one most often missed (The Refactoring Loop).
when Almost never; the surcharge has to be enormous and the behaviour well understood.
cost You must reproduce behaviour nobody has written down, under a deadline, with no incremental release path (The Risk in a Rewrite).
How to build it
Most important first.
- Measure the surcharge the only way that is honest: record, for a handful of changes in the area, how many modules and tests each touched. That is a model of your own system, not a metric to publish (Change Amplification).
- Compare repayment against the *accumulated* surcharge over a realistic horizon rather than against a single change, which is the comparison that makes repayment look unaffordable.
- Repay where the frequency is, not where the ugliness is. Frequency times surcharge is what you are minimising.
- Stop the growth before repaying the principal: adding a shared corpus test, or forbidding new copies, caps the compounding at once and costs a day (Contract Tests).
- Prefer repayments that ride along with work already funded in that area, because that is where the tests are already being run and the review is already happening (The Refactoring Loop).
What the next change costs
The field this whole domain exists for. A structure is only better if it makes the change after this one cheaper — and it is worth saying which changes it does not help.
- The first pricing change after the copy: two edits, one comparison, an hour of extra care. Barely noticeable, and this is why the shortcut looked free.
- The third: four copies exist because the pattern was established, so four edits, several pairwise comparisons, two teams to coordinate, and a day of discovery to be sure the list is complete.
- The fifth: the same four copies plus features built on each, so a change now means understanding four contexts, and one of them has drifted — so part of the work is deciding which behaviour is correct before any editing begins.
- Repayment, if done at the third: about a week, and the fourth and fifth changes cost a day each. Repayment at the fifth: the same week plus the drift reconciliation, plus the features now depending on the divergent behaviour.
- Making interest visible means measuring your own work, which teams reasonably dislike and which can be turned against them by management that misreads it.
- Any model of the surcharge is a model. It is defensible as a shape — "this change touches four modules and used to touch one" — and indefensible as a number, and the line between them is easy to cross under pressure.
- Repaying early is a bet that the area keeps changing. If the product pivots away, the repayment was pure cost and the shortcut was right all along (The Cost of Change).
What can go wrong
- Interest is asserted with a made-up number, the business asks how it was measured, and the credibility of the whole argument goes with the answer.
- The team repays the debt that is most visible rather than the one in the most-changed area, and the next feature is no cheaper.
- Growth is not stopped first, so repayment races against accumulation and loses — three copies become five while the migration is in flight.
- The mitigation fails: recording what each change touches is itself a small ongoing tax, and teams abandon it after four weeks, which leaves the trend unmeasured again.
- The surcharge depends on how often the area changes, which is a product roadmap fact rather than an engineering one.
- Repayment depends on tests that would notice a behaviour change, and where those are missing the first repayment is really a test-writing project (Characterization Tests).
- "Interest means a percentage." The metaphor borrows the word for compounding, not for arithmetic. There is no rate, and inventing one converts a real argument into a fake measurement (What Technical Debt Actually Is).
- "So all debt compounds." Only debt in areas that keep changing. Debt in stable code has no interest payments and can be carried forever (When Design Does Not Pay).
- "Repay the highest-interest debt first." Repay where frequency and surcharge are both high *and* the repayment is bounded. A high-interest item that costs a quarter to repay may still lose to three cheap ones (The Trade-off Matrix).
- "We can stop the interest by freezing the area." You can, and you have then frozen the part of the product that changes most, which is a business decision rather than an engineering one.
- duplicate-knowledge
- shotgun-surgery
- god-object
Testing it, and how it ages
- A shared corpus test across the copies caps the growth of interest immediately, before any structural work (Contract Tests).
- When repaying, test the behaviour the consumers rely on, not the structure being removed, so the tests survive the change (What a Unit Is).
- Record the number of test files each change in the area touches; it is the cheapest available proxy for the surcharge and it costs nothing to collect (Change Amplification).
- Interest rises fastest right after the debt becomes popular, because each new consumer both pays the surcharge and adds to it.
- It falls to zero the moment the area stops changing — a shortcut in a frozen module is a curiosity, not a cost, which is why old code is not automatically expensive (What "Legacy" Actually Means).
- Left long enough, the surcharge is absorbed into the team's sense of normal velocity, at which point nobody can name the debt because everything is equally slow.
Where this applies
This domain's advice is contested more than most. These labels say what each claim is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view rather than a caricature.
- SIMULATEDThe edit and test counts in this lesson come from an Engineer Atlas model of a small commerce codebase, not from measurement of a real system. The shape transfers — copies multiply, comparisons grow faster than copies, discovery cost rises with each consumer — and the specific counts do not. Treat any figure here as an illustration of a mechanism, never as a benchmark for your own codebase.
- GENERALCompounding follows from later work being built on earlier work, which is true of any codebase in any language; what varies is the multiplier, since a strongly typed codebase makes some of the discovery mechanical and a dynamic one leaves all of it manual.
- CONTESTEDThe strongest opposing view is that the compounding story is unfalsifiable and self-serving: change costs rise for many reasons — bigger systems, more users, more compliance, more people — and attributing the rise to a specific shortcut is a narrative rather than a finding. Teams that have tried to measure it honestly often cannot separate the signals. The defensible core is narrower than the metaphor: the number of places a given rule lives is directly observable, and so is the number of edits per rule change.
Where the depth lives
This domain teaches the codebase-level structure and hands the rest off.
- — Testing & Reliability Engineering — capping interest with a shared corpus across several implementations is a testing technique, and how far its coverage can be trusted belongs there.