SKILL.md
Deprecation and Migration
Code is a liability, not an asset. Every line costs maintenance, patches, and onboarding overhead, so code that no longer earns its keep gets removed. Hyrum's Law makes this hard: with enough users, every observable behavior gets depended on, so deprecation requires active migration, not an announcement.
The Deprecation Decision
Answer these five before deprecating anything:
- Does the system still provide unique value? Yes: maintain it. No: proceed.
- How many consumers depend on it? Quantify with metrics, logs, and dependency analysis.
- Does a replacement exist? No: build it first. Never deprecate without an alternative.
- What does migration cost each consumer? Trivially automatable: do it. Manual and heavy: weigh against maintenance cost.
- What does NOT deprecating cost? Security exposure, engineer time, complexity tax.
Then pick the mode. Advisory: warnings, docs, users migrate on their own timeline. Default to this. Compulsory: hard removal date, required when security risk or maintenance cost justifies forcing it, and only valid if you ship migration tooling, docs, and support with the deadline.
Migration Workflow
- Build the replacement. It must cover all critical use cases of the old system, have docs and a migration guide, and be proven in production, not just theoretically better.
- Announce and document. Publish a deprecation notice: status and date, replacement, removal date or "advisory", reason, and a concrete step-by-step migration guide. Read references/patterns.md when writing the notice; it has the template.
- Migrate incrementally. One consumer at a time: identify touchpoints, switch to the replacement, verify behavior matches, remove old references, confirm no regressions. The Churn Rule: if you own the infrastructure being deprecated, you migrate your users or ship backward-compatible updates. Announcing and walking away is not deprecation, it is abandonment.
- Remove. Only after verified zero active usage: delete the code, its tests, docs, config, and finally the deprecation notices themselves.
For the strangler, adapter, and feature-flag migration patterns with code shapes: read references/patterns.md when choosing how to run old and new in parallel.
Zombie Code
Code nobody owns but everybody depends on: no commits in months with active consumers, no maintainer, failing tests nobody fixes, vulnerable dependencies. Zombie code gets one of two outcomes, an assigned owner with real maintenance, or a deprecation plan. Limbo is not an option.
Verification
Before removal, measure usage: check metrics, access logs, and run a repo-wide search for imports and references to the old system. Expect zero active consumers and zero code references. If usage is not zero, you are not done migrating; removal now is an outage, go back to step 3.
After removal, run the full build and test suite. Expect green. If anything breaks, a hidden consumer existed; restore, find it, migrate it.
Good vs Bad
Judgment call: a team wants to sunset an internal API "next quarter".
Bad: Send an email announcing the removal date and mark the endpoints deprecated. Consumers ignore it, the date slips forever, or removal day becomes an incident.
Good: Inventory the 9 consuming services from gateway logs, ship an adapter plus a migration guide, migrate the 3 you own, open PRs for 4 more, escalate the last 2 with the deadline, and remove only when the logs read zero for two weeks.
Footguns
- Deprecating with no replacement. Users cannot move to nothing, so nothing moves. Fix: replacement first, proven in production.
- Trusting the announcement. "Users will migrate on their own." They will not. Fix: tooling, incentives, or do the migration yourself.
- Keeping the old system "just in case". Two systems doing one job doubles maintenance, tests, and onboarding forever. Fix: compare 2-3 years of dual maintenance cost against a rebuild; the rebuild is almost always cheaper.
- Adding features to a deprecated system. Every addition deepens the hole and signals the deprecation is not real. Fix: hard feature freeze on deprecation day, invest in the replacement only.
- Removing based on "nobody uses this, probably". Fix: metrics and logs, not vibes, and a search for stragglers before deletion.
Completion Checklist
- [ ] Five decision questions answered, mode (advisory/compulsory) chosen deliberately
- [ ] Replacement production-proven and covering all critical use cases
- [ ] Migration guide published with concrete steps
- [ ] Zero active usage verified by metrics and repo search before removal
- [ ] Old code, tests, docs, config, and deprecation notices all removed
- [ ] Full suite green after removal
Any box unchecked: not done. Fix or say so.