Technical debt is a product decision
· 5 min read
In my current team we’ve cut technical debt by roughly 80%. When I mention it, the follow-up question is almost always technical: which tool, which refactor, which pattern. My answer tends to disappoint: what made the difference wasn’t technical.
Technical debt is usually framed as an engineering problem that engineering should fix in its spare time. I think that framing is exactly why it so rarely gets fixed.
The thesis
Technical debt isn’t paid off with clean-up sprints. It’s paid off by making it visible in the same language as the rest of the roadmap.
As long as debt lives in an engineering document only engineering reads, it will lose to the next feature every time. Not because product doesn’t care, but because nobody can weigh something they understand (“this feature brings X”) against something they don’t (“this module is badly coupled”).
Ward Cunningham’s original metaphor already said it: debt isn’t bad by definition. Borrowing to ship sooner can be an excellent call. What’s bad is not knowing how much you owe or how much interest you’re paying. And deciding when to borrow and when to repay is, by definition, a product decision.
How to measure it
The first step is to stop talking about debt in the abstract. “There’s a lot of debt” doesn’t let anyone prioritise anything. What works is translating each piece of debt into its interest: what it costs us to keep it.
| Debt (engineering language) | Interest (product language) |
|---|---|
| “The orders service is tightly coupled” | Every checkout change takes twice as long and breaks something elsewhere. |
| “The pricing module has no tests” | Nobody wants to touch it; pricing improvements keep getting postponed. |
| “Each team shapes API responses its own way” | Integrating a new service takes days instead of hours. |
| “Config is edited by hand” | Mistakes reach production and get fixed in a hurry. |
The right-hand column is the one that matters. It doesn’t need to be precise; it needs to be concrete and readable by someone outside engineering.
For tracking it over time, simple signals work and don’t require a metrics project:
- Change frequency × pain. Code nobody touches can be ugly without hurting anyone. The debt that matters is where people work every week.
- Incidents by area. If production bugs cluster in two modules, you know where the interest-bearing debt is.
- Lead time by type of change. If changes in one area are consistently slower than everywhere else, there’s a reason.
How to prioritise it against features
Once debt has a visible interest rate, it can be compared with everything else. From there, my criteria are simple:
1. Pay debt where you’re about to build. The best time to clean up a module is right before adding features to it. The refactor stops being a separate cost and becomes part of shipping that feature faster and with less risk. Product doesn’t have to choose.
2. Leave the quiet areas alone. Rewriting stable code nobody touches is the most expensive way to feel productive. If it doesn’t charge interest, it isn’t urgent.
3. Name new debt. Borrowing on purpose to hit a date is legitimate, as long as it’s recorded: which shortcut, what it will cost, when it gets revisited. The dangerous debt is the debt nobody decided to take on.
4. A small, steady budget beats a big project. “Tech debt quarters” tend to get cancelled the moment a commercial priority shows up. A sustained share of every cycle survives almost anything.
None of these is an engineering rule. They’re agreements between engineering and product, and that’s why they work: both sides understand what’s gained and what’s lost.
Coding standards as prevention
Paying debt off is half the job. The other half is creating less of it.
Part of our work was defining and rolling out coding standards across the whole department. Not a style guide nobody reads, but agreements on how a service is structured, how things are named, how errors are handled and what a code review checks.
Standards reduce debt for a slightly counter-intuitive reason: most debt isn’t born from bad decisions, but from many reasonable decisions made differently. Five reasonable ways of solving the same thing add up to a system nobody fully understands. A standard removes four of them and frees attention for what’s actually new.
For a standard to stick, I’ve seen three things work:
- A machine enforces it, not a person. Anything a linter, a formatter or CI can check shouldn’t consume human review time.
- It’s written with the teams, not for them. An imposed standard is respected only while someone is watching.
- It explains the why. Rules without a reason get broken as soon as they get in the way. Rules with one can be debated and improved.
Internal tooling follows the same logic. When a repetitive task is done by hand, everyone does it slightly differently, and every variant leaves a small trail of debt. Automating it with a shared tool standardises it without asking anyone to comply. In our case, some of those tools sped up other teams’ content creation by up to 95% and cut down their errors.
What doesn’t work
Some patterns show up in almost every conversation about technical debt, and they’re worth avoiding:
- The big rewrite. It promises to fix everything at once, takes three times as long as planned, and meanwhile you maintain two systems. Replacing piece by piece is almost always better.
- The endless inventory. Listing every bit of existing debt without prioritising produces a list so long it paralyses instead of helping.
- Debt as a bargaining chip. If engineering uses debt to justify delays, product stops trusting any conversation about it.
- Counting lines of code or isolated code smells. Easy to count, but they don’t tell you where it hurts.
The uncomfortable conclusion
If your team’s technical debt isn’t going down, the problem probably isn’t technical skill. It’s that debt isn’t part of the same conversation as everything else.
Getting it there takes something less glamorous than a big refactor: translating it into cost, deciding with product what gets paid and what doesn’t, and keeping it from growing back with standards nobody has to remember. Reducing debt isn’t a technical project: it’s a way of making product decisions with all the information on the table.