Managing Technical Debt
Telling deliberate shortcuts from accumulated mess, and getting repayment onto a roadmap.
A Metaphor With A Point
The word has since expanded to cover everything unpleasant in a codebase, which weakens it. Separating the categories matters because they need different responses.
| Category | Response |
|---|---|
| Deliberate and prudent | Repay on the schedule you set when you took it |
| Accidental — the team has learned since | Refactor as you touch the area |
| Rot — the world moved, the code did not | Upgrade deliberately; it only worsens |
| Bad code | Not debt. It is a defect, and calling it debt excuses it |
Measuring The Interest
Debt is only worth paying down where it is charging interest. Some of it never will be — a module nobody touches, on a service due for retirement, costs nothing to leave alone.
| Interest shows up as | Measure |
|---|---|
| Changes take longer than they should | Cycle time on that area |
| Every change breaks something | Change failure rate, incidents per release |
| Only one person can touch it | Bus factor — a risk, not just a cost |
| Onboarding is slow | Time to first meaningful change |
| Builds and tests crawl | Pipeline duration — paid on every commit |
| Fear of deploying | Deployment frequency falling |
Paying It Down
| Approach | When it works |
|---|---|
| Opportunistic — improve what you touch | Continuous, invisible, and the default |
| A budget — a fixed share of each cycle | Sustained improvement without a business case per item |
| Targeted project with a delivery goal | When one area blocks something the business wants |
| Strangler pattern — new alongside old, migrate gradually | Replacing a large component safely |
| Big-bang rewrite | Almost never |
The strangler pattern is the credible alternative: route a slice of traffic to the new implementation, migrate a piece at a time, keep both running until the old one is unused. It is slower on paper and finishes, which the rewrite frequently does not.
Not Accumulating It
| Practice | Effect |
|---|---|
| Record the shortcut when you take it | A dated ticket, not a comment nobody greps for |
| Boy-scout rule | Leave each file slightly better than you found it |
| Keep dependencies current continuously | Small upgrades instead of one impossible jump |
| Delete dead code and unused flags | The cheapest debt repayment available |
| Treat the pipeline as product | Slow builds tax every change forever |
| Review architecture at boundaries | Catch drift while it is still cheap to correct |
Interview Questions
What is technical debt, precisely?
A deliberate shortcut taken to ship sooner, understood at the time and repaid later with interest. Bad code is a defect, not debt — conflating them excuses it.
How do you decide what to pay down?
By the interest it charges: cycle time, change failure rate, incidents and onboarding cost in that area. Debt in code nobody touches is free to leave alone.
How do you make the business case?
In delivery terms rather than aesthetics — "this area takes three times longer to change and causes most of our incidents" is fundable; "the code is ugly" is not.
Why do rewrites usually fail?
They restart at zero features against a moving target while the old system still needs maintaining, and every undocumented behaviour has to be rediscovered by breaking it.
What is the strangler pattern?
Building the replacement alongside the original and migrating a slice at a time until the old one is unused. Slower on paper, and it finishes.
Which debt is most underestimated?
Dependency rot. Deferred upgrades compound until a routine bump becomes a migration project, and an unupgradeable version forces the rewrite you were avoiding.