Technical Debt Is a Business Argument, Not an Engineering One

Table of Contents
- Why “We Need to Refactor” Always Loses
- Not All Debt Is the Same Thing
- The Metaphor Is Better Than You Think
- Measuring Debt in Units Anyone Cares About
- Which Debt to Pay and Which to Keep
- Making the Case That Gets Approved
- Paying Debt Without a Rewrite
- Common Pitfalls
- Conclusion
- Frequently Asked Questions
Key takeaway: Technical debt only gets funded when it is expressed as a cost the business is already paying. “This code is ugly” is an aesthetic claim. “Changes to billing take three weeks instead of three days” is a business case.
Why “We Need to Refactor” Always Loses
An engineer says the payment module is a mess and needs rewriting. A product manager says the customer needs a feature by the end of the quarter. The feature wins. This happens repeatedly until the engineer stops asking.
The usual interpretation is that management does not value quality. That is occasionally true and usually wrong. What is actually happening is a failure of translation.
The engineer is making a claim about internal properties — coupling, duplication, missing tests, confusing structure. These are real and consequential. They are also invisible to anyone not reading the code, and they carry no units that fit into a prioritisation decision.
The product manager is comparing two things: a feature with an estimated revenue impact and a date, versus an unquantified request to spend engineering time producing no visible change. Framed that way, choosing the feature is not short-sightedness. It is the only decision the available information supports.
The engineer’s mistake is arguing about the code. The code is not the argument. The argument is what the code costs — and that cost is already being paid, in slower delivery, more incidents, and time spent working around problems rather than solving them.
Not All Debt Is the Same Thing
“Technical debt” gets applied to several unrelated situations, which makes the conversation muddy. Separating them helps, because they warrant different responses.
Deliberate, documented debt. A shortcut taken knowingly to meet a deadline, recorded with the intent to address it. This is legitimate engineering judgement — the shortcut bought something real. It becomes a problem only when it is never revisited.
Deliberate, undocumented debt. The same shortcut without the record. Six months later nobody remembers it was deliberate, and the workaround looks like the intended design. This is where most compounding damage originates.
Accidental debt from learning. Code written correctly given what the team knew at the time, which the domain has since outgrown. Nobody erred. The requirements moved.
Environmental drift. Dependencies aged out of support, deprecated platform APIs, expiring runtime versions. This category has a deadline set by someone else, which makes it the easiest to fund and the most dangerous to ignore.
Not debt at all. Code that is unfamiliar, written in a style the current team dislikes, or simply not how you would do it. Rewriting working code because it is unfashionable is not debt repayment. It is preference with a serious-sounding label, and conflating it with real debt undermines the credibility of every genuine request.
That last category matters most for the argument. Teams that cry debt about style choices find nobody believes them when the payments platform is genuinely failing.
The Metaphor Is Better Than You Think
The debt metaphor is often criticised as imprecise. It is actually precise in the ways that matter, and the precision is useful when talking to people who think about money.
Principal is the work needed to fix the underlying problem.
Interest is the ongoing extra cost of not fixing it — every feature that takes longer, every bug that recurs, every incident traced to the same source.
Interest rate varies enormously by location. Debt in code nobody touches accrues almost nothing. Debt in the module every feature passes through accrues constantly.
This framing produces the single most important insight for prioritisation: the interest rate matters more than the principal. A large mess in a stable, rarely-modified component may be entirely rational to leave alone indefinitely. A small mess in the busiest part of the codebase can cost more per quarter than fixing it would cost once.
It also explains why debt compounds rather than accumulating linearly. Workarounds built on workarounds are harder to remove than either alone. Missing tests make every subsequent change riskier, which makes changes slower, which makes people avoid the area, which lets it degrade further. Undocumented shortcuts get copied by engineers who assume they were intentional.
Anyone who has managed a budget understands compounding interest immediately. That is why this framing works where “the code is bad” does not.
Measuring Debt in Units Anyone Cares About
The measurement problem is solvable, and mostly with data you already have.
Change lead time by area. How long from starting work to shipping, broken down by component. If billing changes consistently take four times longer than comparable changes elsewhere, that ratio is your evidence. It is measurable from version control and issue tracking without any new instrumentation.
Defect density and recurrence. Which components generate the most incidents, and which incidents keep recurring. Recurring incidents in one area indicate a structural problem rather than a series of unrelated mistakes.
Onboarding time to productivity. How long before a new engineer can safely change a given component. Long ramp-up in one area is a direct signal about comprehensibility, and it has an obvious salary cost attached.
Estimate inflation and variance. Where estimates are consistently exceeded, and where variance is highest. High variance signals that engineers cannot predict what they will encounter — a reliable indicator of hidden coupling.
Change failure rate by area. Which components break production most often when modified.
The single most persuasive artefact you can produce is a two-column comparison for the same class of change in a healthy area versus a debt-laden one:
| Reporting module | Billing module | |
|---|---|---|
| Median change lead time | 3 days | 17 days |
| Change failure rate | 4% | 31% |
| Incidents last quarter | 1 | 14 |
| Engineers who will touch it | 9 | 2 |
That final row is the one that tends to end the discussion. Two people being able to modify a revenue-critical system is a business risk expressible without reference to code quality at all.
Which Debt to Pay and Which to Keep
Not all debt should be repaid, and saying so improves your credibility considerably.
Pay it when: the area changes frequently, it blocks planned work, it causes recurring incidents, it concentrates knowledge in too few people, or an external deadline exists such as an end-of-support date.
Keep it when: the code is stable and rarely modified, the component is scheduled for replacement anyway, the business context is uncertain enough that the requirements may change again, or the fix costs more than the accumulated interest will.
Never pay it for: style preferences, framework fashion, or the desire to work with newer technology. These are worth pursuing through other means and should not be labelled debt.
A useful discipline is maintaining an explicit debt register with an estimated interest rate per item — roughly how much time it costs per month. Items with negligible interest can be closed as accepted rather than lingering as guilt. This makes the list shorter, more credible, and more likely to be taken seriously when you do bring items forward.
Making the Case That Gets Approved
Concrete reframings that change outcomes:
Instead of “the payment code is unmaintainable” say “payment changes take three weeks instead of three days, and we have four payment features planned this quarter — this is costing us roughly eight weeks of delivery”
Instead of “we have no tests here” say “31 percent of changes to this component cause a production incident, compared to 4 percent elsewhere”
Instead of “we need to refactor before adding features” say “we can build this feature in six weeks on the current structure, or three weeks with two weeks of preparation first — the second option is faster if we ship more than one thing here”
That last construction is the strongest available, because it competes on the dimension the business already cares about: total time to value. It also concedes something important — that the shortcut is sometimes correct — which makes you a credible advisor rather than someone who always wants to rewrite things.
Two further tactics help. Attach debt work to features that touch the same area, so the case is “this feature plus fixing what makes it slow” rather than a separate unfunded request. And time-box explicitly: “two weeks, and here is what will be measurably different” is fundable in a way that “a few months of cleanup” is not.
Paying Debt Without a Rewrite
Large rewrites fail at a notorious rate, and there are better mechanisms.
Improve on contact. Every change to a file leaves it slightly better — a name clarified, a test added, a function extracted. This costs almost nothing per change and concentrates effort exactly where change frequency is highest, which is exactly where the interest rate is highest.
Strangle rather than replace. Route traffic through a new implementation incrementally, path by path, while the old one continues serving everything else. Each step is independently valuable and reversible, which is the opposite of a big-bang rewrite’s risk profile.
Add tests before changing, not after. Characterisation tests that capture current behaviour — including behaviour you consider wrong — make subsequent restructuring safe. This is the highest-leverage first step in almost any legacy area.
Isolate before improving. Wrapping a messy component behind a clean interface lets everything else be written against the good interface immediately, and lets the mess be replaced later without touching callers. This delivers most of the benefit before any of the hard work.
Delete aggressively. Unused code, dead feature flags, abandoned experiments. This is the cheapest debt reduction available and it is routinely skipped because deleting feels less productive than building.
Common Pitfalls
Proposing a rewrite as the first option. It has the highest cost, the highest risk, and the longest time before any benefit. It should be a last resort, not an opening position.
Labelling preferences as debt. This is the fastest way to lose credibility on the entire topic.
Refusing to ever take on debt. Deliberate shortcuts are legitimate engineering decisions. An engineer who never accepts one is not a careful engineer; they are an inflexible one.
Hidden debt work. Fixing things without telling anyone means the improvement is invisible, unattributed, and produces no evidence for the next request.
No measurement. Without before-and-after numbers, completed debt work generates no support for future work.
Waiting for permission. Improve-on-contact requires no approval and compounds quietly. Most debt reduction should happen this way rather than as funded projects.
Conclusion
The technical debt conversation fails because engineers argue in terms of code properties while decisions are made in terms of cost, risk, and time. The properties are real; they are simply not the argument.
Translate them. Measure lead time, change failure rate, incident recurrence, and how many people can safely modify each area. Present debt as interest already being paid rather than as an investment being requested. Distinguish clearly between debt worth fixing and debt worth keeping, because the willingness to say “leave that alone” is what makes the rest believable.
Then do most of the work incrementally, on contact, without asking. Time-boxed proposals with measurable outcomes get approved; open-ended cleanup does not. And the strongest argument you will ever have is a completed example: this area was slow, we changed it, here is the before and after.
Frequently Asked Questions
How much time should be allocated to debt work? A commonly cited figure is 15 to 20 percent of capacity, and the number matters less than consistency. Sporadic large efforts work worse than continuous small ones, because debt accrues continuously.
How do I justify this to a manager who only tracks feature delivery? Use their metric. Show that feature delivery in the affected area is measurably slower, and frame the debt work as an investment in delivery speed. Never present it as competing with features — present it as enabling them.
Is a rewrite ever the right answer? Occasionally: when the platform is genuinely end-of-life, when the domain has changed so fundamentally that the model no longer fits, or when the existing system cannot meet a hard requirement. Even then, incremental replacement usually beats a parallel rewrite.
What if leadership never approves debt work? Do the improve-on-contact version, which requires no approval, and collect measurements. A demonstrated improvement with numbers attached is a much stronger basis for the next conversation than any projection.
How do I stop new debt accumulating? Definition of done including tests and documentation, review standards that catch structural problems, and a habit of recording deliberate shortcuts when they are taken. That last one is cheap and prevents intentional decisions becoming mysterious legacy.
Should the debt register be visible to non-engineers? Yes, with business-relevant framing — impact and estimated cost rather than implementation detail. Visibility is what makes it a shared priority rather than an engineering complaint.
What about debt in code nobody understands anymore? Start with characterisation tests that document current behaviour, including apparent bugs. Understanding must precede change, and tests are how understanding gets recorded in a form that survives the person who acquired it.


