Technical debt is not old code. It is a known design or delivery compromise that makes future change, reliability, security, or support more expensive. Treat it as a product risk with evidence, not a moral judgement about the original implementation.
Find debt through real work
Start with recent incidents, slow features, recurring support issues, difficult onboarding, failed deployments, and manual repairs. Trace one painful request path. Record the symptom, root constraint, affected capability, and evidence: logs, cycle time, incident count, or code-path coupling.
Avoid a generic “refactor the backend” ticket. A useful debt item is specific: “Membership checks are duplicated in six endpoints, producing inconsistent access behavior” or “CSV imports cannot be retried safely after a timeout.”
Estimate impact, not just effort
Score each item on user impact, likelihood, cost of delay, security or data risk, and the amount of future work it blocks. Then estimate the smallest safe intervention. Some debt needs an urgent guardrail; some can be paid down alongside the next feature; some is simply a documented tradeoff.
Pay it down incrementally
Use a sequence such as:
- Add tests or monitoring around current behavior.
- Create a narrow boundary or compatibility layer.
- Move one caller or data path at a time.
- Measure the new path and remove the old one later.
This is often safer than a rewrite because it produces value while preserving the system’s working behavior. Reserve rewrites for cases where evidence shows incremental migration cannot meet the required constraint.
Use the 30-day existing-codebase checklist to build the evidence before prioritizing the work.