DebtSIMULATEDGENERALCONTESTED

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 question

The shortcut cost us a week to take. Why has it cost far more than a week to live with?

The requirement

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 obvious build

The shortcut cost a week. If we ever need to fix it, it will cost about a week. Until then it is free.

Why it breaks

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.

How it breaks as requirements change
  • 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.
RequirementConstraintsInvariantsResponsibilitiesBoundariesInterfacesStateDependenciesFailureImplementationTestsFeedbackEvolution

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.

Constraints
  • 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.
Invariants
  • 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.

Responsibilities
  • 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).
Boundaries
  • 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

SIMULATEDBoth columns are model outputs over a teaching codebase rather than measurements. What is transferable is the relationship — copies grow with the popularity of a concept, comparisons grow faster than copies, and drift appears once the count exceeds what one person keeps in mind. The absolute figures are specific to this fictional system and should not be quoted as a rate.

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.

The same pricing change, six months apart
The change

Add a promotional discount that applies to the order subtotal before tax. Identical requirement both times.

Month 1: the rule exists in the checkout module and one copy in the report
CheckoutReport
testscheckout_testreport_test
2 modules · 2 test files

Two edits, one comparison, an afternoon. Everyone concluded the copy was harmless, and given what was in front of them that conclusion was reasonable.

Month 6: four copies, each with features built on it, and one of them has drifted
CheckoutReportInvoicePdfPartnerExportRenewalJob
testscheckout_testreport_testinvoice_testexport_contract_testrenewal_test
5 modules · 5 test files

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.

what it cost Consolidating onto one owner — the repayment — would cost about a week and would make the seventh and eighth pricing changes cheap. It also creates a coordination point that three teams now queue behind, forces the partner export to accept a rounding correction it has been quietly relying on for months, and spends a week that the roadmap wanted for a feature. The comparison the business needs is that week against the accumulated surcharge on the changes it expects to ask for, and if pricing is about to be frozen for a year the honest answer is to carry the debt.

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 ruleEdits per changePairwise agreements to checkWhat actually goes wrong
110Nothing. This is the state you are trying to return to.
221Nothing yet, which is why the second copy always gets approved.
333One is forgotten occasionally; caught in review about half the time.
446Drift 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.

An area is getting more expensive to change

What does the next year of changes in this area cost under each response?

Repay now

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.

Cap the interest

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).

Carry it deliberately

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).

Repay opportunistically

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).

Rewrite the area

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.

Cost of the next change
  • 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.
What the recommended approach costs
  • 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

Failure modes
  • 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.
Dependencies, and their direction
  • 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).
Misreads
  • "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.
Smells this explains
  • duplicate-knowledge
  • shotgun-surgery
  • god-object

Testing it, and how it ages

What to test, and at which boundary
  • 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).
How this design ages
  • 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.

Domains that do not exist yet
  • 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.