How to Quantify & Prioritize Technical Debt
← Back to blogEngineering

How to Quantify & Prioritize Technical Debt

J
Jason Miller
· 10 min read

Ward Cunningham coined the "technical debt" metaphor in 1992. More than thirty years later, it remains one of the most useful and most abused concepts in software engineering.

Useful, because the debt analogy is accurate: you can borrow against future quality to ship faster today, and that borrowing accrues interest. Abused, because teams use "technical debt" to describe everything from genuinely problematic architectural decisions to code someone wrote that doesn't look the way they'd write it.

The result: important debt gets lost in a sea of noise, and engineering teams struggle to make a credible case for addressing it.

This is a framework for actually doing something about it.

What technical debt actually is

Cunningham's original meaning was specific: technical debt is the extra work you take on when you knowingly cut corners to ship faster, with the intention of paying it back later.

There are also the accidental varieties — things that made sense at the time but became problematic as requirements changed, team changed, or scale increased. These are legitimate debt too.

What's not technical debt:

  • Code you don't like but that works fine
  • Things written in patterns you wouldn't choose today but that aren't causing problems
  • Perfectly functional code that just needs documentation

The test: is this thing actively costing you in velocity, reliability, or onboarding? If not, it's aesthetic preference, not debt.

Four categories that actually matter

Not all technical debt is equal. Focus on these four:

1. Architectural debt — Decisions made at a smaller scale that don't hold at current scale. A monolith that made sense at 5 engineers that's now causing deploy contention with 50. A sync architecture that made sense at 1,000 RPM that's now causing cascading failures at 100,000 RPM.

2. Reliability debt — Missing error handling, absent circuit breakers, no retry logic, no dead letter queues. Things that let failures propagate rather than degrade gracefully. This debt pays interest in incidents.

3. Observability debt — Code that's hard to debug when it fails. No structured logging, no distributed tracing, no meaningful metrics. When something breaks in production and you're guessing, this is why.

4. Knowledge debt — Undocumented systems, tribal knowledge concentrated in one or two people, bus factor of one. This pays interest when people leave, and when new engineers have to reverse-engineer things that should be obvious.

Measuring the cost

The moment you can put a number on debt, conversations with non-engineers become dramatically more productive.

Velocity impact

How much time per sprint is the team spending on debt-related rework, debugging debt-adjacent issues, or working around known problems? Have the team track this explicitly for two or three sprints.

If the answer is "40% of our time," that's 40% of your engineering salary budget being paid to service debt interest. On a 10-engineer team at $150k average loaded cost, that's $600k/year in lost capacity.

Incident attribution

For every incident in the last six months, trace it to a root cause. How many had a contributing technical debt factor? Add up the engineer-hours spent on incident response, multiply by your cost-per-engineer-hour, and add the estimated customer impact.

Onboarding time

How long does it take a new engineer to become productive? The delta between "could be productive" (a well-structured codebase with good documentation) and "actually productive" is knowledge and documentation debt in disguise.

If your answer is "three months," and a well-managed codebase would be six weeks, that's six weeks of $150k/year salary — ~$17k per new hire — being spent on debt interest. Multiply by your annual hiring rate.

Change failure rate

What percentage of deployments require a hotfix or rollback? The DORA metrics framework defines this as "change failure rate." High change failure rate is almost always a signal of testing debt and reliability debt.

Prioritization framework

Once you have costs, you can prioritize rationally. Score each item:

Risk (1-5): How likely is this to cause an incident, data loss, or security issue?

Velocity cost (1-5): How much engineering time is this consuming weekly?

Payoff period (1-5): How quickly would paying this down return value?

Priority score = Risk × Velocity cost × Payoff period

High-risk items with ongoing velocity cost and fast payoff periods go to the top. Low-risk items with minimal ongoing cost and long payoff periods go to the backlog.

Getting organizational buy-in

Technical debt conversations fail when engineers present them as technical problems. Executives don't have the context to evaluate "we need to refactor our authentication layer" — but they can evaluate "our authentication system caused two outages this year, is on a framework with a known security vulnerability, and changes to it take 3x longer than comparable changes in other parts of the codebase. At current rates, we expect it to cost us another $200k in incident response and delayed features over the next 12 months."

Three things that help get buy-in:

Connect to business outcomes — frame debt in terms of release frequency, incident frequency, engineer hiring and retention (good engineers don't stay in bad codebases), and customer impact.

Propose a specific allocation — "20% of every sprint on debt" is an easier sell than "a 3-month debt-paydown project." It's less scary, more sustainable, and it keeps debt visible week over week.

Measure and report — track velocity trends, incident counts, and onboarding time before and after. Make the improvement visible.

Making it sustainable

Debt paydown fails when it's treated as a one-time project. The codebase that needs a three-month refactor today will need another one in two years if the underlying practices don't change.

Sustainable debt management:

  • Budget for it explicitly (20% sprint allocation is a common choice)
  • Include debt reduction in the definition of "done" for features — you leave the code better than you found it
  • Review architectural decisions before shipping, not after (ADRs, architecture reviews for significant changes)
  • Track DORA metrics regularly so drift toward debt becomes visible before it's severe

Technical debt isn't a moral failure. It's a byproduct of building software under real constraints. The teams that manage it well are the ones that make it visible, measure its cost, and treat it like the financial obligation it is.

We help engineering teams quantify technical debt and build the practices to manage it sustainably. Get in touch if this resonates.

Working on something similar?

We help engineering teams implement the practices covered in this post. First call is free.

Start a conversation →