The debts we carry
Why does a fifteen-year-old company with a thousand engineers sometimes ship slower than a five-person startup?
The engineers didn’t get worse. The answer lives in this lesson, and it’s the single most useful piece of engineering empathy a product person can own.
What is technical debt?
Start with a scene, two weeks before Black Friday.
The coffee company wants gift cards for the holiday. The right design is a proper gift-card system with its own tables and its own service, and it needs four weeks. The deadline allows two. So the team wedges the gift-card logic directly into the checkout code, somewhere it doesn’t belong, with a special case for every payment path. It works, it ships on time, and Black Friday is a hit.
Look at what the wedge left behind. Checkout now quietly does two jobs, and every payment path carries a gift-card special case. Nothing is broken today.
The cost lands on the future: anyone who changes checkout from now on must first understand those special cases, then work around them without breaking one. The shortcut made checkout permanently harder to change.
The team just took out a loan. The industry’s name for it is technical debtConcept · lights on your maptechnical debtShortcut code still doing its job while quietly taxing everything built near it. Some of it is deliberate strategy (speed now, paid for later), and the real danger is letting the interest compound unwatched., and the finance metaphor is not decoration. The term was coined in 1992 by the programmer Ward Cunningham precisely so that non-engineers could reason about it.
It works because the mechanics match. The shortcut is the principal. And like all debt, it charges interest:
Notice what the ledger shows. The borrowing took one sprint, but every later feature that passes near the shortcut pays a tax (extra time, extra bugs, extra fear) forever, until the principal is paid.
Borrowing was still probably the correct business call. Companies take loans to seize opportunities; Black Friday was one. The sin is never the borrowing. It’s borrowing every sprint and repaying nothing, until the whole team’s velocity is spent on interest.
That is the thousand-engineer company from the opening question, and the cause is not worse engineers but fifteen years of accumulated, rational, unpaid loans.
What is a legacy system?
Give debt enough years and it hardens into something with its own name: the legacy systemConcept · lights on your maplegacy systemSoftware that outlived its builders and became infrastructure: too important to turn off, too poorly understood to change casually. Engineers say the word with dread and respect at once; failure never lasts long enough to earn it..
Take the coffee company’s original ordering system, built in 2012 by two founders who left years ago. It still processes every order, and it has few tests and no documentation. Its code assumes one café, one currency, and a menu that never changes.
That was the world of 2012, and a decade of workarounds has been layered on top to fake everything since. Nobody currently at the company fully understands it, and everyone is afraid to touch it, precisely because it matters so much.
This is not a small-company quirk. A large share of the world’s banking still runs on systems written decades ago in COBOL, a language most working engineers have never used, kept alive because they are load-bearing and terrifying in exactly this way.
So hear the word correctly. “Legacy” sounds like an insult, but it’s actually a battle scar. Only successful software lives long enough to become legacy.
And notice what last lesson’s ADRs were really for. A legacy system with a decision record is merely old, while one without it is old and unexplained.
What is refactoring?
Debt has a repayment tool: refactoringConcept · lights on your maprefactoringRearranging code so it is easier to work on, without changing what it does — users notice nothing, future engineers notice everything. The renovation that keeps a lived-in codebase livable, and the roadmap item hardest to defend because success looks like nothing happened., restructuring code’s insides while its outside behavior stays identical.
Watch it happen to the delivery-fee math:
Read the before half first. Three screens need the delivery fee, so three components each grew a private copy of the math, and copies drift: a fee change applied to one is a bug lurking in the other two.
The refactor pulls the calculation into one shared delivery_fee() function and points all three callers at it. Fees come out exactly as they did before. What changed is the future: the next fee change is one edit in one place, not three edits in three.
The definition has a hard edge worth respecting. Behavior must not change. That is what makes refactoring safe and checkable: same inputs, same outputs, verifiably. A “refactor” that also adds features has lost that safety and is just… changes.
And the invisibility creates the political problem you are now equipped to solve. A sprint of refactoring produces nothing a user can see, so it dies in roadmap meetings, unless someone in the room can argue its case. The argument is a debt-service argument: “two weeks of refactoring makes every delivery-adjacent feature faster for a year” is a real and often true sentence. Perhaps you, now, are the one who says it.
What is maintenance?
Loans and repayments are the dramatic events. Underneath them runs a quieter constant. The ongoing work of keeping software alive at all is maintenanceConcept · lights on your mapmaintenanceEverything a product needs just to stay standing while nobody adds a thing. On mature software it outweighs feature work (the budget surprise every founder eventually meets), and skipping it is how products quietly rot., and it is the least visible work in software.
A typical week of it: updating dependencies (Module 3’s versions march on, and some updates patch security holes that cannot wait), fixing the small bugs support keeps reporting, and paying interest on every loan this lesson has described.
The real number shocks stakeholders. Mature products routinely spend half or more of all engineering time just staying alive, before the first new feature of the quarter is touched. A building stands once built; software is closer to a garden, tended or dead.
When a thousand-engineer company seems to ship like a hundred-engineer one, this is where the other nine hundred are, keeping yesterday’s promises running.
What is a workaround?
The debt family has one more resident, small and easy to underestimate. A workaroundConcept · lights on your mapworkaroundTriage that got comfortable: the extra manual step, the weekly restart, the special case bolted on. Honest as a stopgap; the trouble begins when the temporary patch quietly acquires a pension. routes around a problem instead of solving it.
Watch one being born. The nightly sales report crashes for cafés with very large order histories. The real fix is a week of work; the team is mid-sprint. So an engineer sets a reminder and reruns the report by hand every Monday morning. It takes ninety seconds a week, and it is completely reasonable.
Now watch it calcify. Two years later, that engineer is gone. The Monday rerun is a calendar event titled “DO NOT SKIP,” performed faithfully by someone who inherited it, for reasons nobody can state. No ticket was filed, no ADR written. It is now a load-bearing mystery. Remove it and something, somewhere, breaks.
That is the double nature to remember: fine as triage, terrible as permanence. Every legacy system is partly a museum of workarounds nobody remembers the reasons for, and the difference between triage and permanence is usually just a ticket that never got filed.
The mental model to remember
Technical debt is the cost of past shortcuts, and it charges interest. Every future change near the shortcut pays a tax until the principal is paid. Borrowing to hit a date can be right; never repaying is the sin.
A legacy system is debt matured into infrastructure: old, load-bearing, half-understood, still processing the payroll. A battle scar, not an insult.
Refactoring is the principal payment: cleaner insides, identical behavior, nothing for users to see, which is why it must be defended by its future payoff.
Maintenance is the steady state: half or more of a mature product’s engineering time spent keeping yesterday’s promises running.
A workaround is a tiny unrecorded loan: fine as triage, dangerous as permanence.
And the opening question has its answer. The old company isn’t slower because its engineers got worse; it is paying interest on fifteen years of rational borrowing. You should now be able to hear “we need a sprint to refactor” not as engineers polishing for pleasure but as a debt-service proposal, and judge it the way a CFO would.
Feature requests near the ordering code keep coming back with shocking estimates. An engineer says: “Everything near ordering costs triple — that area is pure debt. Give us a sprint to refactor and the next year of ordering features gets cheap.” As a stakeholder, the wise read is:
▼ answer the check to continue ▼