Technical Debt Is Not Always Bad. Unmanaged Technical Debt Is.
by Eric Hanson, Backend Developer at Clean Systems Consulting
The Metaphor Worth Taking Seriously
Ward Cunningham coined the technical debt metaphor in 1992, and it's one of the more honest framings in software engineering. The key insight of the original metaphor is often lost: debt is not bad by definition. Businesses take on financial debt intentionally because the return on the borrowed capital exceeds the cost of carrying the debt. That's rational.
Technical debt is the same: you make a design decision that is expedient now but will require rework later. If the rework cost is lower than the benefit of shipping faster, taking on the debt was the right call. The mistake is not taking on debt — it's not tracking it, letting it compound invisibly, and losing the ability to make deliberate repayment decisions.
The Kinds of Debt Worth Distinguishing
Not all technical debt has the same cause or the same treatment:
Deliberate, prudent debt: "We know the right way to do this, but doing it the right way would take two weeks and we need to ship in four days. We'll take the shortcut and fix it next sprint." This is the textbook case. The debt was conscious, the tradeoff was considered, and there's an intent to repay.
Inadvertent debt: "We didn't know there was a better approach when we built this." Not negligence — just the result of learning. You know more now than you did. The design reflects what you understood then.
Reckless debt: "We don't have time to do this right." Said under pressure, without a plan to fix it, repeated across a codebase until the interest payments consume all available velocity. This is the failure mode.
The distinction matters because the remediation is different. Deliberate debt has a repayment plan. Inadvertent debt needs to be identified and evaluated. Reckless debt needs to stop accumulating before it can be paid down.
The Interest Payment Problem
Technical debt has interest in the form of slower delivery. A system with high debt levels takes longer to change because every change requires working around or through the accumulated shortcuts. New features require understanding a convoluted codebase. Bugs are harder to isolate. The time cost of debt is ongoing and compound.
The problem with compound interest on technical debt is that it's invisible on individual PRs. Each individual change is "just slightly harder" than it would be in a clean system. The aggregate effect — that your team is delivering at 60% of potential velocity because of accumulated debt — is rarely measured and almost never attributed correctly. Teams experiencing this often blame other things: unclear requirements, team churn, testing overhead.
The first step to managing debt is making its cost visible.
Making Debt Visible and Deliberate
A technical debt register is a simple mechanism: a tracked list of known debt items with rough cost estimates. Not a JIRA sprint board — a lightweight document where known shortcuts are named, their locations are specified, and their estimated impact on velocity is noted.
## Technical Debt Register
### High Priority
- **OrderService synchronous validation**: Validates payment instrument
synchronously in request thread. Blocks under payment provider latency.
Estimated fix: 3 days. Impact: P99 latency spikes under load.
### Medium Priority
- **N+1 in product recommendations**: Loads recommendation metadata
per-product in a loop. Acceptable at current volume, will hit database
hard at 5x current scale.
Estimated fix: 1 day. Impact: minor now, significant at scale.
### Known But Low Priority
- **Legacy config format**: Config loaded from .properties and YAML mixed.
Confusing for new engineers. No correctness impact.
Estimated fix: 2 days. Impact: onboarding friction only.
This doesn't need to be exhaustive. It needs to capture the items that are actually affecting velocity so that when planning capacity, debt repayment can be deliberate.
The Repayment Strategy
Debt repayment rarely succeeds as a dedicated "cleanup sprint" — these get cancelled when priorities shift. The more durable approach is continuous, small repayments:
- The boy scout rule: leave every file you touch slightly cleaner than you found it. Fix one thing that's been bothering you every time you open a file for another reason.
- Time-boxed debt budgets: 15-20% of each sprint allocated to debt work, not negotiable downward. This keeps the interest from compounding indefinitely.
- Pay before you extend: before building new functionality on top of a known debt area, evaluate whether the debt makes the new work significantly riskier or harder. If yes, debt repayment is a prerequisite, not optional.
The Practical Takeaway
Create a technical debt register for your current codebase — not a comprehensive audit, just the items your team talks about most. Estimate the velocity cost of each one. Bring it to the next planning session and allocate 15% of capacity to addressing the highest-cost item. Do that every sprint, consistently, and watch delivery speed increase over time as the interest payments get smaller.