Skip to content
Back to Maintenance & LTS

Debt Prioritization

Rank debt by interest rate (how fast it compounds) and principal (cost to pay), not by what's loudest.

Why

Not all debt is equal, and paying the wrong debt first is as bad as paying none. A duplicated utility function (low interest — it doesn't grow) can wait, while an untested payment path (high interest — every new feature adds untested branches) compounds daily. The economic framing — principal (hours to fix) and interest rate (how fast it blocks new work) — lets you rank objectively instead of by who complained last. High-interest, low-principal debt is the best first paydown: small effort, large unblocking. High-principal, low-interest debt can be deferred indefinitely. This is the same logic as financial debt: pay the high-APR credit card before the low-APR mortgage.

When

When the debt catalog has >10 items. Re-prioritize quarterly or when a new high-interest debt appears.

How

1. For each debt item, estimate principal (hours to fix) and interest (how much it slows the next feature, 1-5)
2. Compute priority = interest / principal (high interest, low principal = pay first)
3. Bucket: pay-now (high ratio) | pay-next-quarter (medium) | accept (low ratio, old)
4. Within pay-now, sort by blast radius: payment/auth/data-loss debt before UI debt
5. Schedule pay-now items into the next 2 sprints as explicit tickets, not "when we have time"
6. Re-evaluate after each paydown: did the interest rate drop? sometimes paying one debt reveals a higher one

Example

# Debt prioritization matrix
| ID  | Principal | Interest | Ratio | Bucket     |
|-----|-----------|----------|-------|------------|
| D2  | 4h        | 5        | 1.25  | pay-now    | # untested payment
| D7  | 2h        | 4        | 2.00  | pay-now    | # auth bypass risk
| D1  | 2h        | 2        | 1.00  | next-q     | # dup validation
| D3  | 16h       | 2        | 0.13  | accept     | # react major (defer)
| D5  | 8h        | 1        | 0.13  | accept     | # old CSS framework

# Schedule pay-now into sprints (not "when free")
Sprint 42: D7 (auth bypass, 2h) — security, do first
Sprint 43: D2 (payment test coverage, 4h)

# Accept D3/D5 explicitly in DEBT.md:
# "D3 react@16: accepted 2024-03-15, revisit at Q3 upgrade window"

Common Problems

  • ⚠Paying the loudest debt (the one a senior dev complained about) instead of the highest-interest — feels productive, isn't.
  • ⚠Paying high-principal, low-interest debt first (a big rewrite) — ties up a sprint and the unblocking effect is minimal.
  • ⚠No acceptance bucket — every debt item stays "to do" forever, so the list loses credibility and people stop using it.

Best Practices

  • ✓Rank by interest/principal ratio — this is the debt-paydown analog of paying high-APR debt first in personal finance.
  • ✓Always have an explicit "accept" bucket — accepting debt with a revisit date is a decision; leaving it ambiguous is not.
  • ✓Schedule pay-now debt as sprint tickets with hour estimates, not as a wish list — debt that isn't scheduled isn't paid.