80 lines
3.5 KiB
Markdown
80 lines
3.5 KiB
Markdown
---
|
|
name: safe-deprecation-and-migration
|
|
description: Use when replacing or retiring an API, feature, dependency, service, or database schema. Plans measured, reversible migrations with compatibility periods, incremental consumer cutover, expand-contract data changes, and verified removal.
|
|
license: MIT
|
|
source: adapted from https://github.com/addyosmani/agent-skills/tree/main/skills/deprecation-and-migration (MIT)
|
|
---
|
|
|
|
# Safe Deprecation and Migration
|
|
|
|
Treat removal as a migration, not a deletion. Do not announce a replacement
|
|
until it covers critical use cases and do not remove the old path until measured
|
|
usage reaches zero.
|
|
|
|
## Decide with evidence
|
|
|
|
Before changing anything, inventory:
|
|
|
|
- the old system's unique value and current owner;
|
|
- all known consumers and touchpoints (code, jobs, configs, docs, data);
|
|
- usage from logs/metrics, including a time window that covers infrequent jobs;
|
|
- undocumented behavior consumers may rely on;
|
|
- replacement readiness and per-consumer migration cost;
|
|
- maintenance, security, and opportunity cost of keeping both paths.
|
|
|
|
Choose advisory deprecation when the old system remains safe and supportable.
|
|
Use a compulsory deadline only when risk or maintenance cost justifies it, and
|
|
pair it with tooling, documentation, ownership, and support.
|
|
|
|
## Build the migration plan
|
|
|
|
Define these before cutover:
|
|
|
|
1. Replacement behavior and known gaps.
|
|
2. Compatibility mechanism: adapter, dual-read/write, feature flag, or traffic
|
|
splitting.
|
|
3. Consumer-by-consumer order, owner, and completion signal.
|
|
4. Observability that distinguishes old and new usage and compares outcomes.
|
|
5. Advance, hold, rollback, and final-removal criteria.
|
|
6. Exact rollback actions, including what happens to data written by the new
|
|
path.
|
|
|
|
Migrate one bounded cohort or consumer at a time. Verify behavior and telemetry
|
|
before expanding. Prefer owning teams to migrate their consumers or provide an
|
|
automatic compatibility layer; a warning alone is not a migration.
|
|
|
|
## Use expand-contract for data shapes
|
|
|
|
Never rename or drop a live field/column in the same release that changes the
|
|
code using it. Use separately deployable phases:
|
|
|
|
1. **Expand:** add the new nullable shape alongside the old one.
|
|
2. **Dual-write:** populate both shapes for new changes.
|
|
3. **Backfill:** migrate existing data in throttled, restartable batches.
|
|
4. **Switch reads:** read the new shape while continuing dual writes; bake and
|
|
compare results.
|
|
5. **Contract:** stop old writes, prove no reads remain, then drop the old shape
|
|
in a later release.
|
|
|
|
Make every phase safe while old and new application versions coexist. For large
|
|
tables, avoid long locks; use the datastore's online/concurrent mechanisms.
|
|
Design and test the down path before merging. If a data transformation is not
|
|
reversible, state that explicitly and use backups/checkpoints plus a forward
|
|
repair plan instead of pretending a code rollback restores data.
|
|
|
|
## Remove completely
|
|
|
|
Only remove the old path after telemetry shows zero use for the agreed window
|
|
and every consumer is signed off. Then remove its code, flags, adapters, tests,
|
|
configuration, dashboards, alerts, and obsolete documentation together.
|
|
|
|
Verify afterward:
|
|
|
|
- no code/config/doc references remain;
|
|
- the replacement handles production traffic normally;
|
|
- rollback or forward-repair remains available through the observation window;
|
|
- temporary compatibility logic and dual writes are gone.
|
|
|
|
Do not let a supposedly temporary adapter or feature flag become a permanent
|
|
second system: assign an owner and expiry date when creating it.
|