Prioritizing Technical Debt
"We'll fix tech debt later" usually means never, until the payments module takes down Black Friday and later arrives as a five-month rewrite with no feature work. Technical debt is not moral failure — it is deferred work with compounding interest. The engineering failure is listing eighty vague "cleanup" tickets PMs cannot prioritize against revenue features. Debt gets funded when it is scored, visible, and tied to outcomes leadership already cares about: reliability, speed to market, and security audits that do not fail.
Name the type of debt
Martin Fowler's quadrant helps conversations:
| Reckless | Prudent | |
|---|---|---|
| Deliberate | "Ship now, no tests" | "Ship MVP, schedule migration Q2" |
| Inadvertent | "Didn't know pattern" | "Now we know — refactor" |
Different types need different owners. Reckless-deliberate requires process fix; prudent-deliberate needs calendar commitment; inadvertent needs learning, not blame.
Measure interest, not guilt
Interest = ongoing cost of not fixing:
- Incident rate — PagerDuty tags on
legacy-billing - Lead time — PRs touching
monolith/vsservices/(DORA metrics) - Defect density — bugs per story in area
- Onboarding time — new hires stuck on module
## Debt item: Replace sync XML parser in ingest pipeline
- Incidents: 3 Sev-2 last quarter (parser OOM)
- Cycle time: +2.3 days avg vs other ingest changes
- Security: CVE-2024-XXXX in libxml2, no patch path except rewrite
- Effort estimate: 3 engineer-weeks
- Interest score: HIGH
Numbers beat "this code smells."
Prioritization formula (practical)
Score 1–5 each:
Priority = (Business risk + Velocity drag + Security) × Blast radius / Effort
| Item | Risk | Velocity | Security | Blast | Effort | Score |
|---|---|---|---|---|---|---|
| Auth token library EOL | 4 | 3 | 5 | 5 | 2 | high |
| Rename variables in utils | 1 | 1 | 1 | 1 | 1 | low |
Top quartile enters roadmap negotiation. Bottom quartile — delete ticket or do opportunistically when touching file anyway (boy scout rule).
Debt budget mechanisms
- Fixed capacity — 15% sprint points for debt/theme epic
- Rule of three — every third sprint debt-focused
- Feature coupling — "Checkout v2 includes retiring v1 debt"
- SLO-triggered — error budget spent → next cycle debt priority
Pick one and communicate externally. Stealth 100% feature sprints accumulate silent debt until catastrophic.
Thematic epics PMs understand
Instead of "refactor UserService," propose:
Epic: Retire monolith checkout (Q1)
Outcome: 40% faster checkout experiments, PCI scope reduction
Milestones:
M1: Read path behind flag (2 wks)
M2: Write path migration (3 wks)
M3: Delete legacy (1 wk)
Risks if deferred: cannot launch wallet; audit finding open
Same work, fundable narrative.
When not to prioritize debt
- Code not changing and not on outage path — leave alone
- Aesthetic preferences without measured drag — skip
- Rewrites for resume-driven architecture — challenge hard
Opportunistic cleanup during feature work is free; dedicated debt sprints are expensive — spend them where interest is proven.
Making debt visible to leadership
Executives fund outcomes, not refactorings. Translate debt into their vocabulary:
Reliability framing: "The billing module caused 3 Sev-2 incidents last quarter costing ~$40k in SLA credits. The proposed migration reduces incident probability by an estimated 80% based on similar migrations."
Velocity framing: "Teams touching the monolith checkout average 8-day PR cycle time vs 2 days for microservice areas. Checkout v2 requires retiring monolith debt — we cannot hit the Q2 launch without it."
Security framing: "Auth library reaches EOL in March with no patch for CVE-2024-XXXX. Migration is 3 engineer-weeks; alternative is accepting audit finding and potential breach exposure."
Attach a one-page brief to roadmap requests with incident links, DORA metrics screenshots, and explicit "cost of not doing this."
Debt inventory hygiene
Debt backlogs rot like any backlog. Quarterly review process:
- Archive stale items — no incidents, no recent changes, no security finding → close ticket
- Merge duplicates — "refactor auth" and "migrate auth tokens" are probably the same epic
- Re-score survivors — incident rates and cycle times change; rescore with current data
- Promote top 3 to epics — everything else stays tagged but unprioritized until next quarter
Cap the active debt backlog at 20–30 items per team. More than that means the scoring isn't ruthless enough.
Tracking debt paydown
Measure whether debt investment actually reduces interest:
## Before/after: Ingest pipeline rewrite (Q1)
Before:
- Incidents: 3/quarter (OOM on XML parser)
- Avg PR cycle time in ingest/: 4.2 days
- p99 ingest latency: 45s
After:
- Incidents: 0 in Q2 post-migration
- Avg PR cycle time in ingest/: 1.8 days
- p99 ingest latency: 12s
Publish before/after in eng all-hands. PMs and leadership see ROI; engineers see their debt work mattered. Without measurement, debt sprints feel like thankless cleanup.
Organizational anti-patterns
- Stealth debt sprints — eng allocates 20% capacity but doesn't tell product; trust erodes when features slow mysteriously
- Debt as punishment — "you shipped fast, now fix it" demoralizes; debt is a planning outcome, not retribution
- Infinite rewrite — "rewrite everything in Rust" with no business driver; challenge scope aggressively
- No debt budget ever — 100% features for 18 months, then catastrophic outage forces 6-month rewrite
- PM-unreadable tickets — "clean up UserService" tells product nothing; use thematic epics with outcomes
Production checklist
- Debt items scored with incident rate, cycle time, and security data
- Top quartile debt visible in product backlog with PM access
- Fixed capacity (15%) or feature-coupled debt budget agreed with product
- Thematic epics with outcome statements, not micro-refactor tickets
- Quarterly debt inventory review with archive/rescore/promote cycle
- Before/after metrics published after debt paydown
- Debt type classified (Fowler quadrant) with appropriate response
Resources
- Technical Debt Quadrant (Martin Fowler)
- DORA metrics overview
- Manage technical debt (Google SRE workbook)
- Prioritizing debt (Camille Fournier)
- Architecture decision records for debt context
Frequently asked questions
How do I convince product to allocate time for tech debt?
Frame debt as risk and throughput tax with numbers: incident frequency tied to module, cycle time inflation on changes touching legacy area, or outage cost. Propose bounded debt budget (15–20% capacity) or tie debt work to feature prerequisites — 'shipping X requires migration Y first.'
What is the best scoring model for tech debt items?
Combine impact (incident risk, dev velocity drag, security exposure) × reach (teams affected) × effort inverse. Simple spreadsheet beats elaborate frameworks nobody updates. Re-score quarterly — debt rots in priority queues too.
Should tech debt have its own backlog or live in the product backlog?
Visible in product backlog with PM visibility, tagged DEBT or tagged by theme (observability, auth migration). Hidden eng-only backlogs get zero airtime. Thematic epics ('retire monolith checkout') communicate better than 200 micro-tickets PMs cannot parse.
Hiring a senior Android / Flutter engineer?
I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.
Get in touch →