Craft of code
Selling tech debt
Fund cleanup with incident rate, speed, and risk — not "this code is messy" — and show progress on a dashboard.
"This code is messy" does not fund work. Translate debt into outcomes a stakeholder already cares about. Propose a thin vertical slice with a measurable exit, not an open-ended "rewrite billing."
The same translation belongs in status updates and promotion packets. Risk reduction is the story, not aesthetics.
Walking through the pitch
Pick the language that matches the pain:
- Incident rate — "This module caused 3 Sev-2s; characterization plus seam work cuts MTTR."
- Delivery speed — "Pricing changes estimate at 2 weeks because of entanglement; after extract, similar changes took 2 days."
- Hiring and onboarding — "New engineers avoid this area; risk concentrates on two people."
- Compliance or security — "Auth checks are copy-pasted; a missed path is an audit finding."
A pitch that works: "two weeks to get pricing behind tests and a flag, then feature X ships on the new path."
Lead status with operational metrics, not vibes:
- Percent of traffic or tenants on the new path
- Diff rate between parallel-run old vs new (should trend toward ~0)
- Error budget or Sev count attributable to the area
- Median time to implement a typical change in that module, before vs after
- Lines of dead legacy deleted only after traffic is gone
Promotion cases love a measurable strangler: "migrated 80% of checkout pricing traffic to the new engine with zero Sev-1s; deleted 3k lines of dead branch." Tie it to ownership and delivery.
The social side
Legacy code is often political. The original authors left, the domain expert is overloaded, or prior cleanup burned trust.
- Pair with the domain expert for characterization fixtures, not a six-week lecture.
- Show a demo of parallel-run diffs matching on real traffic samples.
- Keep blast radius small so skeptics can say yes to a pilot.
- Credit prior work in write-ups. You are continuing a story, not shaming history.
SDE2s leave legacy better than they found it on the path of delivery. You do not need permission to extract a function behind tests. You do need a plan and stakeholders for multi-quarter migrations.
When a rewrite is justified
Rarely, incremental strangling costs more than a bounded rewrite: a prototype that became production with no users yet, a module smaller than its test harness would be, or a technology mandate with a hard deadline and isolation already in place. Even then, rewrite behind a facade with parallel run, not a flip of DNS on day 180.
Ask: can we characterize today's behavior? Can we route gradually? If both answers are no, add seams and tests first.
Common mistakes
- Selling cleanliness. Committees fund incidents, speed, and risk.
- Open-ended rewrite billing. Name a two-week slice and an exit.
- Status as "cleaned up files." Show % traffic, diff rate, and Sev count.
- Boiling the ocean. Stop when the next feature is easy.
Check yourself
-
Your manager asks why pricing cleanup matters. What do you say first? Last changes took 2 weeks; after extract they took 2 days — or the 3 Sev-2s this module caused.
-
Traffic on the new engine is 80% and diffs are ~0. What is the victory lap? Ramp the rest, then delete the dead legacy. Deletion comes last.
Key takeaways
- Translate debt into incidents, speed, risk, and onboarding — not messiness.
- Propose a thin slice with a measurable exit.
- Share a dashboard: traffic %, parallel-run diffs, Sevs, time-to-change.
- Keep the social blast radius small, and rewrite only when strangling costs more.
Further learning
Back to the map on refactoring and legacy.
Related
Refactoring and legacy code
Change code you did not write without breaking it. Start here for characterization, seams, tiny steps, and incremental migrations.
Incremental migrations
Replace a system the way a strangler fig replaces a host — route by route, with expand/contract and parallel run, never a six-month freeze.
Ownership
Acting like an owner: close loops, care about outcomes, and be the person things do not fall through with.