Technical Debt Is Not Bad Code — It's a Strategic Decision
The Word Nobody Uses Correctly
"We have so much technical debt!" Every engineering team says this. But when you ask them to define it, you get: "The code is messy," "We didn't write tests," "The architecture is wrong."
That's not technical debt. That's just bad code.
Ward Cunningham, who coined the term, was very specific: technical debt is a deliberate decision to ship something that you know isn't optimal, in exchange for speed, with a plan to fix it later. The key word is deliberate.
Technical Debt (deliberate, strategic):
"We're shipping with a hardcoded config file instead of a proper
config service because we need to launch by Friday. We'll build
the config service in Sprint 3."
→ Known shortcut, documented, has a repayment plan
NOT Technical Debt (just bad code):
"Nobody wrote tests and the code has no structure."
→ Not a decision. Just negligence. No repayment plan.
NOT Technical Debt (bit rot):
"The framework is 5 years old and no longer maintained."
→ Not a deliberate decision. Just entropy over time.
The distinction matters because the solutions are completely different.
The Four Types of Code Quality Issues
| Type | Cause | Solution | Priority |
|-------------------|--------------------|----------------------|------------|
| Technical Debt | Deliberate choice | Scheduled repayment | Planned |
| Bad Code | Lack of skill/time | Refactoring + review | Ongoing |
| Bit Rot | Time and entropy | Modernization plan | Quarterly |
| Missing Features | Scope limitation | Product backlog | Prioritized|
When teams lump everything into "technical debt," they create a vague, overwhelming backlog that never gets addressed. When you categorize correctly, each type gets the right treatment.
Managing Real Technical Debt
Step 1: The Debt Register
Every deliberate shortcut gets documented:
// In your project wiki, README, or ADR (Architecture Decision Record)
interface TechDebtItem {
id: string;
description: string;
dateIncurred: string;
reason: string; // Why we took the shortcut
impact: "low" | "medium" | "high";
interestRate: string; // How much it costs us over time
repaymentPlan: string; // How and when we'll fix it
owner: string; // Who's responsible
}
// Example entry
const debt: TechDebtItem = {
id: "TD-042",
description: "Order processing uses synchronous API calls instead of event queue",
dateIncurred: "2026-01-15",
reason: "Event infrastructure not ready, needed to launch order system by Feb 1",
impact: "medium",
interestRate: "Checkout latency increases ~100ms per new integration added",
repaymentPlan: "Migrate to event-driven in Q2 after infrastructure team delivers message bus",
owner: "backend-team",
};Step 2: The Interest Rate
Every debt item has an "interest rate" — the ongoing cost of not fixing it:
High Interest (fix soon):
→ Slows down every developer who touches this area
→ Causes production incidents regularly
→ Prevents launching critical features
→ Example: No CI/CD pipeline → every deploy is manual and risky
Medium Interest (schedule fix):
→ Adds friction to some workflows
→ Occasional issues but manageable
→ Workarounds exist but waste time
→ Example: Hardcoded config → need deploy to change any setting
Low Interest (fix when convenient):
→ Minor inefficiency
→ Doesn't affect most work
→ No customer impact
→ Example: Unused code that should be cleaned up
Focus repayment on high-interest debt first. Low-interest debt can wait — sometimes indefinitely.
Step 3: The 20% Rule
Allocate a consistent percentage of sprint capacity to debt repayment:
Sprint Capacity Allocation:
Feature work: 70%
Technical debt/quality: 20%
Innovation/exploration: 10%
For a 2-week sprint with 5 engineers (50 engineer-days):
Features: 35 engineer-days
Debt/quality: 10 engineer-days
Innovation: 5 engineer-days
The 20% isn't negotiable. When debt repayment is optional, it never happens. When it's a fixed allocation, the team consistently improves the codebase alongside feature delivery.
Communicating Debt to Business Stakeholders
Engineers say "technical debt." Business hears "we want to rewrite everything and deliver no features for a quarter."
Reframe it in business terms:
Instead of: "We need to refactor the order system."
Say: "Our checkout takes 8 seconds because of sequential API calls.
Fixing this will reduce cart abandonment by an estimated 15%,
which is $200K/year in recovered revenue."
Instead of: "We have a lot of tech debt."
Say: "New features are taking 3x longer than they should because
our deployment process requires 4 hours of manual work.
Automating this will save 40 engineering hours per month."
Instead of: "The code is a mess."
Say: "We had 12 production incidents last quarter caused by the
same subsystem. Fixing it reduces incidents and saves $X
in engineering time and customer impact."
The Debt Budget
When taking on new debt, be explicit about the cost:
Product: "Can we ship this feature by Friday?"
Engineering: "Yes, but here's the trade-off:
Option A (Friday): Hardcode the pricing logic
→ Shipping by Friday
→ But: Any pricing change requires a code deploy
→ Estimated interest: 2 engineering hours per pricing change
→ Repayment cost: 3 days to build proper pricing config
Option B (Next Wednesday): Build it properly with config
→ Ships 3 days later
→ But: Pricing changes are instant, no deploy needed
→ No ongoing debt
Recommendation: Option A if we're launching a marketing campaign
this weekend. Option B if we can wait until Wednesday."
This is the conversation mature engineering organizations have. It's not "yes" or "no" — it's "here's the cost, you decide."
Technical debt isn't something to eliminate. It's something to manage — like financial debt. Take it on deliberately, document it, pay it down consistently, and never let the interest payments exceed your capacity to deliver. The teams that fail aren't the ones with debt. They're the ones who don't know how much they owe.