Technical debt is the accumulated future cost of choosing a faster solution now over a better one. Ward Cunningham coined it as a financial metaphor, and the part usually lost in retelling is that he considered *deliberate* debt a reasonable tool — you borrow to ship, then you pay it back.
Four kinds, and only two are problems
- Deliberate and prudent — "we know this is the wrong abstraction, we need to validate the market first." A legitimate engineering decision, provided it is recorded.
- Deliberate and reckless — "we don't have time for design." Not debt, just damage.
- Inadvertent and prudent — "now that it works, we can see how it should have been built." Unavoidable and often the most valuable learning you get.
- Inadvertent and reckless — "what's a layered architecture?" A capability gap, and no amount of refactoring time fixes it alone.
How the interest actually gets paid
The interest is not abstract. It shows up as the same measurable things every time, which is what makes debt arguable in a planning meeting rather than a matter of taste:
- Features in the affected area take longer than equivalent features elsewhere.
- Changes there produce more defects than changes elsewhere.
- Onboarding into that module takes noticeably longer.
- Engineers route around it — new code duplicates rather than extends it, which compounds the original problem.
Make the argument in time, not in tidiness
"This code is messy" loses to a feature request every time. "Changes in this module take three times longer than the rest of the codebase and produce twice the defects" is a business case. If you cannot produce that comparison, instrument it before asking for time — the measurement usually wins the argument on its own.
Where AI-generated code changes the picture
Generation has made a specific kind of debt cheaper to create and more expensive to hold. Code that no human on the team has ever fully understood is debt regardless of how clean it looks, because comprehension is what you draw on when it breaks at 2am. Convention drift — four reasonable-looking ways to do the same thing, each generated independently — accumulates faster than anyone reviews it.
Paying it down without a rewrite
Rewrites are how debt paydown usually fails: they take longer than estimated, deliver no user value in the meantime, and frequently reproduce the original problems in new form. What works is boring:
- Pay down the part you are already touching, in the same change.
- Add characterisation tests before changing anything you do not understand.
- Fix the interface first; the implementation behind a good interface can be replaced later, cheaply.
- Delete dead code aggressively — the cheapest debt reduction available and the most consistently skipped.
Frequently Asked Questions
Is all technical debt bad?
No. Deliberate, recorded, serviced debt is how products ship on time. What is bad is unrecorded debt, because nobody can decide when to repay something nobody knows exists.
How much time should we spend on it?
A common heuristic is a fixed share of each cycle, but the better answer is targeted: spend it where measurement says change is slowest, not evenly across the codebase.
Does a rewrite ever make sense?
When the cost of change exceeds the cost of replacement and you can define a boundary to replace behind. Rewriting a bounded service is a project; rewriting a system is usually a multi-year mistake.
References
- Ward Explains Debt Metaphor — Ward Cunningham / c2 wiki
- The Agentic Engineering Trends Report 2026 — SaaSRise
About Jishu Labs
Jishu Labs is a software development company founded in 2016. We build custom software, AI/ML systems, and full-stack web and mobile applications for clients, and we make eight AI tools for software teams.