I was in a planning meeting last year when a senior engineer said, "We need two sprints for technical debt." The product manager asked what that meant specifically. The engineer said, "The code is bad and we need to fix it." The PM asked how it was bad. The engineer said, "It's just... it's debt. We've been accumulating it." The PM moved on to the next feature.
That exchange happens in thousands of companies every week. And every time, both sides walk away thinking the other one is the problem. The engineer thinks the PM doesn't care about quality. The PM thinks the engineer wants to refactor for fun. Both are wrong.
"Technical debt" isn't a real thing. It's a communication failure wearing a metaphor's clothing.
The $2.41 Trillion Miscommunication
Technical debt costs US businesses $2.41 trillion per year, with a repair backlog that has reached 61 billion workdays globally. Developers spend an average of 33% of their time dealing with problems caused by it. In poorly managed codebases, that number climbs to 50-80%.
| Metric | Value | Source |
|---|
| Annual cost to US businesses | $2.41 trillion | CAST 2025 |
| Cost to fix globally | $1.52 trillion | CAST 2025 |
| IT budget lost to debt maintenance | ~40% | SIG |
| Developer time on debt-related work | 33% average | Pragmatic Coders |
| CIOs who say 20%+ of budget goes to debt | 30% | McKinsey |
| Feature delivery slowdown (high-debt teams) | 40% slower | McKinsey |
| Top developer frustration | Technical debt (62%) | Stack Overflow 2025 |
That last stat is telling. Technical debt is the number one cause of developer frustration, cited by 62% of developers in the 2025 Stack Overflow survey — twice as much as the second-most frustrating problem. It demoralizes programmers and makes it difficult to do quality work.
These numbers are real. The problem is real. But the way we talk about it is completely broken.
Ward Cunningham Never Meant This
The term "technical debt" was coined by Ward Cunningham in 1992 after reading Metaphors We Live By. He wanted to explain to his boss why a financial product needed refactoring. His original idea was specific and elegant: when building systems iteratively, your understanding of the problem grows over time, and eventually the code doesn't match your current understanding. The gap between "what you now know" and "what the code reflects" is the debt.
That's it. It was about learning, not laziness.
Cunningham has explicitly said that bloggers confused his metaphor with "the idea that you could write code poorly with the intention of doing a good job later." He's never been in favor of writing bad code. He wished he'd coined the term "opportunity" instead of "debt," because the metaphor "afforded poorly managed feature factories too easily."
The creator of the term thinks it's being misused. That should tell us something.
The financial debt metaphor breaks down in almost every dimension that matters.
Financial debt has clear terms. You know the principal, the interest rate, the payment schedule. "Technical debt" has none of these. When an engineer says "we have a lot of debt," that could mean anything from "this function is poorly named" to "our entire architecture is fundamentally wrong and will collapse under 10x load."
Financial debt compounds predictably. Technical debt doesn't actually compound the way financial debt does. As some critics have noted, the idea that technical debt "compounds" or "cumulates" is largely myth — it's often a steady cost rather than something spiraling to bankruptcy. Some technical decisions get worse over time. Others just sit there being mediocre, forever, causing a constant tax but never a crisis.
Financial debt is taken on deliberately. Most technical debt is inadvertent. You didn't choose to incur it. You didn't know the better approach when you wrote the code. Martin Fowler's Technical Debt Quadrant captures this well — he separates debt into four types based on whether it was deliberate vs. inadvertent and reckless vs. prudent. But in practice, when engineers say "technical debt" in meetings, they lump all four types together as if they're the same problem with the same solution.
Financial debt has a creditor. Nobody is going to foreclose on your codebase. The consequences of technical debt are real but diffuse — slower feature development, more bugs, higher onboarding time, developer frustration. These are all measurable, but nobody measures them because "technical debt" as a concept doesn't demand measurement. It demands sympathy.
That's the core problem. The metaphor is designed to generate agreement ("yes, debt is bad, we should pay it down") without requiring specificity ("exactly which part of the code, what's the impact, what's the fix, and what's the business case").
There's another way the metaphor fails that nobody talks about: financial debt has a clear principal. You know exactly how much you borrowed. With "technical debt," nobody can tell you the size of the debt. Is it $10K of engineering time? $500K? $5M? If you can't quantify it, you can't prioritize it. And if you can't prioritize it, it gets pushed to "someday" — which in software means "never."
This vagueness is why around 40% of the average IT department's budget gets consumed by maintenance work. Not because managers are irresponsible, but because nobody ever translates "tech debt" into language that allows rational resource allocation.
What Engineers Actually Mean (But Don't Say)
When I hear "we have technical debt," I mentally translate it into one of these seven things. They're all different problems requiring different solutions.
| What They Say | What They Mean | The Real Problem |
|---|
| "We have tech debt" | "This code is hard to change" | Coupling / poor abstractions |
| "We have tech debt" | "This system can't handle our current scale" | Architecture mismatch |
| "We have tech debt" | "Nobody understands this code" | Knowledge silos / no documentation |
| "We have tech debt" | "We're using an outdated framework" | Dependency rot |
| "We have tech debt" | "Tests are missing and deploys are scary" | Insufficient test coverage |
| "We have tech debt" | "The code doesn't match our requirements anymore" | Ward Cunningham's original definition |
| "We have tech debt" | "I'm bored and want to rewrite this in Rust" | Resume-driven development |
That last one is real. I'm not saying it's the majority, but it's also not zero. As Help Scout's engineering team put it, the striving for novelty sometimes becomes the driving force for abandoning perfectly suitable solutions under the umbrella of technical debt.
Each of these problems has a different cost, a different urgency, and a different fix. Calling them all "technical debt" is like going to the doctor and saying "I don't feel good." It's true but useless. The doctor needs symptoms, not vibes.
And here's the really uncomfortable truth: some of these aren't problems at all. "We're using an outdated framework" is only a problem if the framework causes bugs, security vulnerabilities, or hiring difficulties. If it works and is maintained, it's not debt — it's a stable technology choice that an engineer finds aesthetically displeasing. I've seen teams burn months rewriting perfectly functional systems in trendier frameworks and calling it "paying down tech debt." It wasn't. It was resume-driven development funded by a vague metaphor.
JetBrains' 2025 survey found engineers spend 2-5 working days per month on tech debt — up to 25% of the engineering budget. How much of that is genuine problem-solving and how much is discretionary "improvement" work that wouldn't survive a cost-benefit analysis? Nobody knows. Because nobody does the analysis. The metaphor protects the work from scrutiny.
The Communication Failure Nobody Admits
Here's what actually happens in most organizations.
Engineers experience real friction. The code is slow to change. Deploys break. Testing is manual and unreliable. They feel the pain daily. It's real and it's demoralizing.
But when they try to communicate this pain to product managers and leadership, they use the "technical debt" metaphor — which is vague, unquantified, and sounds like "let us stop building features to clean up after ourselves." Product managers hear this and think, reasonably, "Every engineer always says this. If we always prioritized this, we'd never ship anything."
So the debt gets deprioritized. Engineers get more frustrated. The code gets worse. The cycle repeats.
The fix isn't to "take technical debt more seriously." The fix is to stop calling it technical debt.
As Eric Normand argues, the remedy is to stop using it as a suitcase word and start being specific. Instead of "we have tech debt," say:
- "This API endpoint takes 4 seconds to respond and we're losing users. Here's the fix, it'll take 3 days."
- "Deploying takes 45 minutes of manual steps. Automating it will take 2 weeks but will save 10 hours/week permanently."
- "This module has zero test coverage. The last three production bugs came from here. Adding tests will take 1 sprint and reduce our incident rate by an estimated 40%."
See the difference? Each statement has a business impact, a cost, and a timeline. A product manager can actually prioritize these. They can say "yes, the API fix is urgent, the deploy automation can wait until Q3, and the test coverage can be 20% of next sprint's capacity."
That's not "paying down debt." That's normal product prioritization with complete information.
The Shopify Rule and Other Ways to Actually Fix This
A few companies have figured out systems that work.
Shopify's 25% Rule
Shopify engineering uses a 25% rule: 25% of engineering capacity goes to maintenance and improvement work, no questions asked, no justification required. This isn't "tech debt sprints" that get canceled when a deadline approaches. It's a permanent allocation built into every team's capacity.
The genius of this approach isn't the 25% number (though McKinsey recommends a similar 15-20%). It's that it removes the negotiation entirely. Engineers don't have to convince product managers that the work is worth doing. The time is allocated. Use it wisely.
Stripe's Programmatic Migrations
Stripe's approach to their million-plus line Ruby codebase is instructive. Their Sorbet project rolled out typing to their entire codebase using programmatic scripts that rewrite the abstract syntax tree — not manual engineer refactoring. They treated code quality as an infrastructure problem, not a character problem.
This matters because it reframes the conversation. Stripe didn't say "our engineers wrote bad Ruby." They said "our codebase grew beyond what untyped Ruby can safely support, and here's a systematic solution." No blame, no guilt, no debt metaphor. Just engineering.
Google's 20% Time (The Real Version)
Google's famous 20% time wasn't really about innovation — it was about giving engineers ownership over the quality of their tools and systems. Most 20% projects were infrastructure improvements, testing frameworks, and developer productivity tools. The most successful companies don't "pay down debt." They invest continuously in developer productivity as a first-class concern.
If you want to actually fix your codebase problems instead of endlessly debating "tech debt," here's the process.
Step 1: Name the Actual Problems
Replace every instance of "technical debt" in your backlog with a specific problem statement that includes:
- What's broken (specific system, component, or process)
- Who it affects (users, developers, ops team)
- How it affects them (latency, error rates, development velocity, onboarding time)
- Proposed fix (specific action, not "refactor")
- Estimated effort (days, not sprints)
Step 2: Quantify the Cost
For each problem, calculate or estimate the ongoing cost:
# Example: Manual deploy process
Deploy frequency: 3x/week
Time per deploy: 45 minutes (2 engineers)
Engineer hourly cost: $85 (loaded)
Weekly cost: 3 × 45min × 2 engineers × $85/hr = $382.50/week
Annual cost: $19,890
Automation effort: 80 hours = $6,800
ROI: 2.9x in year one
Product managers understand ROI. They don't understand "we should pay down our debt."
Step 3: Categorize by Martin Fowler's Quadrant
Use Fowler's quadrant to categorize each problem:
| Quadrant | Description | Action |
|---|
| Deliberate & Prudent | "We knew this shortcut but shipped for the deadline" | Schedule the fix, you already knew what to do |
| Deliberate & Reckless | "We don't have time for design" | This is a culture problem, not a code problem |
| Inadvertent & Prudent | "Now that we understand the domain better, we'd do it differently" | This is learning — plan a migration when it matters |
| Inadvertent & Reckless | "What's a design pattern?" | This is a hiring/training problem |
Each quadrant requires a completely different response. Lumping them together guarantees the wrong solution.
Step 4: Build a Permanent Allocation
Stop negotiating for "tech debt sprints." Build a permanent capacity allocation:
- 20-25% of sprint capacity for improvement work (Shopify model)
- Categorize improvement work alongside feature work, not in a separate backlog
- Track improvement metrics — deployment frequency, change failure rate, lead time, MTTR (the DORA metrics)
- Report progress in business terms — "we reduced deploy time from 45 min to 3 min" not "we refactored the CI pipeline"
Step 5: Stop Rewarding Heroics
The hardest change is cultural. If your organization rewards the engineer who pulls an all-nighter to ship a buggy feature more than the engineer who quietly prevents bugs through good architecture, your "tech debt" problem is actually a management problem.
Companies that actively manage their code quality free up engineers to spend up to 50% more of their time on value-generating work. That's not a nice-to-have. That's a competitive advantage.
The AI-Generated Debt Tsunami
I need to mention the elephant in the room. AI coding tools are accelerating the creation of what people call "technical debt" at an unprecedented rate.
When developers use Copilot, Cursor, or Claude to generate code, the code works — but it often lacks context about the broader system. It duplicates patterns instead of using shared abstractions. It doesn't know about your team's conventions or your system's constraints. And because it's fast, teams ship more of it.
Gartner predicts that by 2026, 80% of all technical debt will be architectural — meaning it can't be fixed with refactoring sprints. It requires deliberate system redesign. AI tools that generate functionally correct but architecturally naive code are accelerating this trend.
This isn't an argument against AI coding tools. They're incredibly valuable. It's an argument for being more precise about the problems AI-generated code creates, rather than dumping them into the vague bucket of "technical debt."
The code AI generates isn't "debt." It's code that works in isolation but may not fit the system. That's a specific problem with specific solutions: better architecture docs, system-aware prompting, human review of structural decisions. Calling it "debt" doesn't help anyone fix it.
What I Actually Think
I think "technical debt" is the most harmful metaphor in software engineering. Not because the problems it describes aren't real — they are, painfully so — but because the metaphor actively prevents those problems from being solved.
Here's why: the debt metaphor positions code quality as a sacrifice — something you give up to ship faster, and then "pay back" later. This framing is wrong in three ways.
First, it implies the original decision was wrong. Most of the time, shipping with imperfect code was the right business decision given the information available. Calling it "debt" makes it sound like someone made a mistake. Nobody made a mistake. Requirements changed, understanding grew, scale increased. That's not debt. That's software development.
Second, it creates an adversarial dynamic between engineering and product. Engineers frame themselves as responsible creditors being ignored by reckless borrowers. Product managers frame engineers as perfectionists who'd rather refactor than ship. The metaphor itself generates the conflict.
Third, it's lazy. Saying "we have technical debt" requires zero analysis. It's a vibes-based assessment that can't be prioritized, can't be measured, and can't be tracked. It's the engineering equivalent of a manager saying "we need to move faster" — technically true and operationally useless.
Here's what I'd replace it with: specific engineering problems with specific business impacts and specific proposed solutions.
Not "we have technical debt in the payments system." Instead: "The payments service has three critical coupling points that force us to coordinate releases across four teams. This adds an average of 6 days to any payments-related feature. Decoupling these systems will take 4 engineer-weeks and reduce the coordination overhead by approximately 80%."
That gets funded. Every time.
The $2.41 trillion "cost of technical debt" isn't really the cost of bad code. It's the cost of engineers and managers failing to communicate in the same language. The code problems are fixable. The communication problem is what's actually costing us trillions.
Stop saying "technical debt." Start saying what you actually mean. The code will get fixed a lot faster.
Sources
- Financial Impact of Technical Debt in 2026
- Pragmatic Coders — How to Calculate the Cost of Tech Debt
- SIG — Technical Debt and IT Budgets
- McKinsey — Tech Debt: Reclaiming Tech Equity
- Stack Overflow — 2025 Developer Survey
- Stack Overflow Blog — 2025 Developer Survey Results
- Martin Fowler — Technical Debt
- Martin Fowler — Technical Debt Quadrant
- Ben Morris — Technical Debt Is an Overused and Lazy Metaphor
- Eric Normand — It's Time to Stop Saying Technical Debt
- Help Scout — The Technical Debt Myth
- Built In — Stop Using Technical Debt as an Excuse
- Shopify Engineering — The 25 Percent Rule for Tackling Technical Debt
- InfoQ — Paying Technical Debt at Scale: Migrations at Stripe
- ARDURA Consulting — Technical Debt 2026
- STEP Software — The True Cost of Technical Debt 2025
- Scalac — How to Tackle Technical Debt Quadrants
- ProductPlan — 6 Ways Product Managers Can Help Manage Technical Debt
- CodeScene — Prioritize Technical Debt by Impact
- Agile Alliance — Introduction to the Technical Debt Concept