Managing Technical Debt Before It Manages You
Technical debt management is one of the most important architectural responsibilities — and the most neglected. Here's how to measure it, prioritize it, and make the case for addressing it.

James Ross Jr.
Strategic Systems Architect & Enterprise Software Developer
The Debt Metaphor Is Imperfect, But It's Useful
Ward Cunningham coined the technical debt metaphor in 1992 to explain why taking shortcuts in software development creates a future cost. Like financial debt, technical debt accrues interest: the longer you carry it, the more expensive it gets to service it, and eventually you can find yourself in a position where servicing the debt consumes more capacity than shipping new value.
The metaphor has since been stretched to cover things it was never meant to describe — bad code that was never intended to be temporary, code written by incompetent engineers, or just any code the current team doesn't like. When everything is "technical debt," nothing is, and the concept loses the urgency it deserves.
For this post, I'm using a more precise definition: technical debt is the implied future cost of expedient decisions made deliberately to ship faster. This includes both the deliberate shortcuts you took with full knowledge of the trade-off, and the inadvertent debt accumulated when solutions made sense at the time but are now limiting.
The Types of Technical Debt That Actually Matter
Not all technical debt is the same, and treating it the same way leads to misallocation of effort. I find it useful to think in terms of four categories:
Deliberate-Prudent Debt
"We need to ship by end of quarter. We'll use this simpler implementation now and refactor it after launch." This is the legitimate use of the debt metaphor. You made an explicit, conscious trade-off with a plan to address it.
This is only not a problem if you actually track it and address it. Most teams do the first half.
Inadvertent Debt
The system accumulated complexity that nobody designed intentionally. The user authentication module was originally straightforward, but 12 engineers added features to it over three years without anyone stepping back to evaluate the overall design. The result is a tangle that's hard to understand and harder to change.
This is probably the most common type and the hardest to see until you're deep in it.
Bit-Rot Debt
Technologies and dependencies decay. The library you chose in 2019 is now unmaintained. The framework version you're running has a known security vulnerability but upgrading it requires a significant migration. The cloud service you rely on has a new, better alternative but migrating isn't free.
This debt accumulates passively and accelerates over time.
Architecture Debt
The fundamental structure of the system doesn't match current requirements. Service boundaries were drawn incorrectly. The data model doesn't reflect the domain. The monolith has grown past the point where a single team can understand it, but no work has been done to create module boundaries.
This is the most expensive type because it affects everything built on top of it.
Measuring What You Have
You can't prioritize debt you haven't measured. Most teams manage technical debt entirely by feel — "we know it's bad over there" — which means the work that gets done is the work that's annoying the most vocal engineers, not the work that's actually limiting the business most.
Quantitative Signals
These metrics won't tell you everything, but they'll tell you where to look:
Change failure rate: What percentage of production deployments cause incidents? High rates indicate architectural instability — the code has become fragile.
Lead time for changes: How long from a feature request to production? Increasing lead times often indicate that the codebase has become resistant to change.
Mean time to recover (MTTR): How long does it take to restore service after an incident? Poor MTTR is often a symptom of debt in observability, logging, or deployment processes.
Test coverage and flakiness: Low coverage creates debt directly (every change is a risk); flaky tests create debt indirectly (engineers stop trusting the test suite).
Dependency age: Running npm outdated or the equivalent in your language tells you how far your dependencies have drifted from current versions.
Qualitative Signals
- Engineers say "that module" in a tone that means danger
- New features consistently require changes in unexpected parts of the codebase
- Onboarding takes significantly longer than it used to
- Runbooks are out of date or don't exist
- Simple changes require coordination across multiple teams
Prioritization: Not All Debt Is Equal
Once you've inventoried your debt, the natural question is where to start. The answer isn't "the worst code" — it's the debt that's costing you the most right now in terms of business impact.
Evaluate each debt item on two axes:
Impact: How much is this slowing down delivery? Is it causing production incidents? Is it limiting what the business can do? Is it a security or compliance risk?
Effort to address: Can this be resolved incrementally, or does it require a significant project? Is the domain well-understood enough to refactor safely?
The debt with high impact and reasonable effort to address is the obvious priority. Don't ignore high-impact, high-effort debt — but break it into smaller, shippable increments rather than planning a six-month rewrite.
Low-impact debt is not necessarily worth addressing. Some code is ugly but stable and rarely modified. If it's not actively creating problems, the cost of changing it might exceed the benefit.
Making the Case to Stakeholders
This is where most technical debt conversations break down. Engineers understand the problem. Business stakeholders, understandably, hear "we want to stop shipping features so we can rewrite code." That's not an easy sell.
The key is translating technical debt into business impact:
Velocity framing: "Adding a new payment method currently takes our team six weeks because of the way the billing module is structured. Addressing this specific piece of debt would reduce that to two weeks for all future payment integrations."
Incident history: "We've had three production incidents in the past six months caused by this authentication module. Each incident costs X hours of engineering time and affects Y customers. Here's what we need to do to stabilize it."
Opportunity cost: "We can't implement feature X that you've asked for because the data model doesn't support it. We have two options: a quick workaround that will create more debt, or a structural fix that takes two sprints and enables not just feature X but also Y and Z."
Avoid abstract arguments about code quality. Business stakeholders don't experience code quality; they experience delivery speed, production reliability, and the cost of features. Connect your debt argument to those outcomes.
Making Progress Without a "Big Debt Sprint"
"Debt sprint" initiatives that dedicate entire quarters to technical debt cleanup are usually ineffective. They're hard to justify to stakeholders, they're demoralizing for engineers who want to build things, and they don't address the systemic problem of how debt accumulates in the first place.
More sustainable approaches:
Boy Scout Rule: Leave every file you touch in better shape than you found it. Refactoring as part of feature work keeps debt from accumulating faster than it's addressed.
20% time for debt: Allocate a portion of each sprint to debt reduction. Make it explicit in planning, not a "if we have time" item that never gets done.
Refactoring gates: Before adding a feature to a module, assess its current state. If it's below a threshold, require the team to address the relevant debt before adding more.
Track it explicitly: Put debt items in your backlog with impact estimates. Make the backlog visible to stakeholders. Invisible debt doesn't get prioritized.
The teams that manage technical debt well aren't the ones that do big cleanup projects. They're the ones that treat debt as a continuous concern — something they measure, communicate about, and address incrementally as part of normal engineering work.
If you're dealing with technical debt that's limiting your team's velocity and want help developing a management strategy, let's talk.