According to the CISQ 2022 Report, technical debt costs companies $2.41 trillion annually. "We'll clean it up after Series A." No you won't. That technical debt isn't debt - it's rot. And rot spreads.
Treat technical debt like compound interest—it grows. Schedule regular debt payments. Ignoring it doesn't make it go away; it makes it worse.
The logic is sound on paper.
The term "technical debt" was coined by Ward Cunningham to explain a deliberate trade-off: shipping faster now for cleanup later. It was supposed to be conscious, like taking a loan for something you can afford to repay. The Software Engineering Institute now defines it as "an element of design that is expedient in the short term, but would result in a technical context that makes future change costlier or impossible."
But that's not how it works. Most "technical debt" isn't a loan. It's deferred maintenance that compounds faster than any interest rate. Unlike debt, you're probably never going to pay it back.
Why "Debt" Is the Wrong Metaphor
Debt implies a few things that aren't true about bad code:
Debt has known terms. You know your interest rate and payment schedule. You can calculate what you owe. Technical debt has no terms. You don't know how much it will cost to fix or when it will bite you.
Debt can be serviced. You can make minimum payments and stay solvent. Technical debt can't be serviced. It either gets fixed or gets worse. There's no "minimum payment" on spaghetti code.
Debt is external. Your loan exists outside your business. Technical debt is inside your codebase, actively making everything harder. It's embedded in every feature you build.
That's why rot is the better metaphor. Rot spreads. Rot makes everything it touches worse. Rot can't be serviced - only excised.
How Rot Compounds
Here's what actually happens with bad code:
Week 1: You ship a quick hack. It works. Nobody notices.
Month 1: Someone else builds on top of your hack. They didn't know it was a hack. Now two things depend on it.
Month 6: A new feature needs to interact with that code. The original author is gone. The new developer works around the weirdness.
Year 1: The hack is now load-bearing. Ten features depend on its weird behavior. Fixing it means rewriting everything that touches it.
Year 2: New hires are trained to work around it. "That module is weird, don't touch it." The hack is now institutional knowledge.
This is compound interest, but on complexity instead of money. And the rate is higher than any financial debt.
"We'll Clean It Up After Series A"
I've heard this at every startup I've worked with. The plan is always the same:
- Ship fast now to hit milestones
- Raise money
- Use the money to hire engineers
- The new engineers will clean up the code
Here's what actually happens:
- You ship fast and hit milestones
- You raise money
- You hire engineers
- The investors want growth, not cleanup
- The new engineers ship more features on top of the rot
- The rot spreads faster because more people are building on it
I've never seen a startup that cleaned up its code after raising venture capital. The pressure to demonstrate growth always wins out over engineering excellence. The cleanup never happens because there's always something more urgent.
The Real Cost of Rot
Let me be specific about what rot costs:
Velocity. Every feature takes longer because you're constantly working around bad code. That 2-day feature takes 2 weeks because you have to understand the archaeology and figure out which assumptions are still valid. According to JetBrains research, engineers spend 2-5 working days per month on tech debt - up to 25% of engineering capacity.
Onboarding. New engineers spend months learning why the code is weird instead of being productive. Institutional knowledge becomes "understanding the workarounds" rather than understanding the actual domain. Documentation can't capture the oral history of why everything is broken.
Morale. Good engineers don't want to work in rotting codebases. They leave. The ones who stay are the ones who can't get jobs elsewhere.
Bugs. Bad code breeds bugs. Those bugs create more workarounds. Those workarounds create more bugs. It's a death spiral.
Eventually, you have to rewrite. Rewrites fail more often than they succeed. Ask Twitter about their rewrite from Ruby to Scala. Ask Netscape about Navigator 5. Bad architecture decisions kill startups long before the market does.
Rot Assessment
Score your codebase to understand how much rot has accumulated:
When to Fix vs When to Rewrite
Here's the brutal truth about rewrites:
Most rewrites fail. The new system takes longer than expected. The old system keeps getting features. The new system has new bugs while the old is "known." Eventually, the rewrite is abandoned.
But sometimes you have no choice. The old system is so rotten that every change is painful. Developers refuse to work on it. Customers leave because features can't ship.
Here's how I decide:
- If the rot is localized - Fix it. Quarantine the bad code, refactor it, replace it module by module.
- If the rot is load-bearing - Build around it. Create clean interfaces that hide the rot. Let the rot stay in its box.
- If the rot is everywhere - Consider a rewrite. But be honest: can you afford 2 years building new while maintaining old?
When Shortcuts Are Worth Taking
I'm not saying shortcuts are always wrong. There are exceptions. Strategic shortcuts make sense when:
- You're validating a hypothesis, not building a product. Throwaway prototypes meant to test assumptions don't need clean architecture. Just make sure they actually get thrown away.
- The code has a known expiration date. Migration scripts, one-time data fixes, and features explicitly scheduled for replacement can be quick and dirty. Document the expiration clearly.
- Speed genuinely determines survival. If shipping this week versus next month is the difference between closing a deal or dying, take the shortcut. But be honest about whether that's really true.
But the 10% of cases where shortcuts are justified doesn't excuse the 90% where they're just laziness disguised as urgency. Most "we had to ship fast" stories are really "we didn't want to do it right."
Write It Right the First Time
The obvious answer is: don't create rot in the first place.
I know, I know. You have deadlines. You have investors. You have competition. You need to ship.
But here's what I've learned in 45 years: time saved cutting corners is always less than time lost dealing with consequences. Always.
The shortcut that saves you a week now will cost you a month later. Maybe not this month. Maybe not this year. But eventually.
I've never looked back at clean, well-tested code thinking "we should have shipped faster." I've looked back at hacks countless times thinking "we should have done this right." Sometimes the best code is deleted code. But that requires code clean enough to understand what's needed.
Practical Advice
If you're already dealing with rot:
Stop the bleeding. Don't add more rot. Every new feature should be clean even if it interfaces with dirty code. Create clean boundaries.
Prioritize based on pain. Code you touch most often should be cleanest. Fix things that slow you down daily.
Make refactoring part of features. "This feature requires touching module X, so we'll clean up module X as part of the work." Tie cleanup to business value.
Be honest about rewrites. If you're going to rewrite, commit fully. Half-hearted rewrites are the worst outcome.
If you're starting fresh:
Write tests. Not because testing is virtuous. Tests let you refactor with confidence. Code without tests is code you can't change.
Refactor continuously. Every PR should leave code a little better than it found it. Small continuous cleanup beats big-bang rewrites.
Say no to shortcuts. The 10% when shortcuts are acceptable doesn't justify the 90% when they're not. Default to doing it right.
Codebase Rot Assessment Scorecard
Score your codebase honestly. High scores indicate rot that needs immediate attention.
| Dimension | Score 0 (Healthy) | Score 1 (Concerning) | Score 2 (Rotting) |
|---|---|---|---|
| Module Isolation | Clear boundaries, minimal coupling | Some tangled dependencies | Everything touches everything |
| Test Coverage | Can refactor with confidence | Some areas covered | Changes break unknowns |
| Onboarding Time | <2 weeks to productivity | 1-2 months | 3+ months of archaeology |
| Workaround Count | Few, documented exceptions | "Known weirdness" in some areas | Oral tradition required |
| Deploy Confidence | Ship anytime, no fear | Prefer certain days/times | Deploys require all hands |
| Change Velocity | Features ship on schedule | Estimates regularly slip | Simple changes take weeks |
The Bottom Line
Technical debt isn't something you pay down later. It's decay spreading through your codebase. The shortcuts you take today become foundations others build on tomorrow. Treat rot like what it is: a threat to your company's future.
"The shortcut that saves you a week now will cost you a month later."
Sources
- Technical Debt — Martin Fowler's exploration of Ward Cunningham's original debt metaphor and how it's evolved (and been misused) over time
- CISQ Technical Debt Standard — The Consortium for IT Software Quality's research showing technical debt has grown to $1.52 trillion, with poor software quality costing $2.41 trillion annually
- Cost of Technical Debt Research — Sonar's study finding that technical debt costs $306,000 per year for a million-line codebase, equivalent to 5,500 developer hours
Code Quality Review
Find the rot before it spreads. Architecture assessment from experience.
Get Assessment