Every engineering organization has a technical debt backlog. Most of them are graveyards — tickets filed with good intentions, never prioritized against feature work, gradually accumulating until someone declares backlog bankruptcy and closes them all.
The problem is not that teams do not know about their debt. It is that knowing is not a mechanism for doing anything about it.
What changed in 2026
- Generated code raised the stakes. Faster code production meant debt accumulated faster, which made the paydown mechanism more consequential.
- Change-cost framing gained ground. Arguing for cleanup based on what the debt costs per change, rather than on code quality abstractions, proved more effective with non-engineering stakeholders.
- Automated hotspot detection improved. Tooling correlating change frequency with complexity made it easier to identify where debt actually hurts.
- Dedicated cleanup time lost credibility. Repeated experience of cleanup sprints being cancelled under delivery pressure pushed teams toward opportunistic paydown.
Track cost, not existence
| Record |
Useful for prioritization |
| This code is ugly |
No |
| This module has high complexity |
Weakly |
| Every change here takes three times longer than it should |
Yes |
| We cannot upgrade this dependency because of this coupling |
Yes |
| Three incidents in six months traced to this |
Yes |
| New engineers take a week to understand this |
Yes |
| This blocks a specific planned feature |
Yes |
The distinction is between describing the debt and describing its interest payments. Nobody prioritizes fixing ugly code against a customer commitment, and reasonably so. Everybody prioritizes fixing something that has caused three incidents and adds a week to every project touching it, because that is a cost expressed in terms the business already tracks.
Where debt exists but costs nothing — code that is unpleasant and never changes — leave it. It is not debt in any meaningful sense; it is just old code that works.
Finding what hurts
The useful signal is the intersection of change frequency and difficulty. Code that changes constantly and is hard to change is where debt is charging interest; code that is hard to change and never changes is not costing you anything today.
Version control history gives you the first half for free — which files change most often. Complexity metrics give a rough second half. The intersection is a short list, and it is usually a much shorter list than the debt backlog.
Incident history is the other strong signal. Repeated incidents in one area are debt announcing itself in the most expensive possible way, and postmortems are where this gets documented — the practice in incident postmortem guide.
Paying it down
Opportunistic paydown works and dedicated cleanup time usually does not. When someone is already working in an area, improving it while they are there is cheap — the context is loaded and the change is being tested anyway. Making that an explicit expectation, with time budgeted into feature estimates rather than tracked separately, is what turns intention into practice.
Reserve dedicated effort for debt too large to address incrementally — a framework migration, a data model change. Those need to be planned and funded as projects, with the cost argument made explicitly. Recording that reasoning is what architecture decision records are for.
Common mistakes
- A comprehensive debt register. Produces a document, not a change.
- Recording existence rather than cost. Cannot be prioritized against features.
- Dedicated cleanup sprints. First thing cancelled under pressure.
- Fixing debt in code that never changes. No interest being charged.
- No connection to incidents. The strongest available argument, frequently unused.
- Treating all debt as equal. Most of it does not matter.
FAQ
How much time should go to debt?
Rather than a fixed percentage, budget it into feature estimates for the areas being touched. Fixed allocations get raided.
How do I justify it to non-engineers?
In their terms: delivery speed, incident frequency, onboarding time. Code quality as an abstract value does not compete with customer commitments.
What about debt in code we plan to replace?
Do not pay it down. Debt in code with a scheduled end date is debt that will be forgiven.
Should debt tickets go in the main backlog?
Where they compete honestly with features on cost, yes. A separate backlog is a separate place to be ignored.
Where to go next
For recording the decisions behind larger changes, read architecture decision records. For incident-driven signals, incident postmortem guide, and for review practices that prevent accumulation, pull request review culture.