with one click
deprecation-and-migration
// 管理弃用和迁移。用于移除旧系统、API 或功能时;用于将用户从一种实现迁移到另一种实现时;用于判断应维护还是下线现有代码时。
// 管理弃用和迁移。用于移除旧系统、API 或功能时;用于将用户从一种实现迁移到另一种实现时;用于判断应维护还是下线现有代码时。
指导稳定的 API 和接口设计。设计 API、模块边界或任何公共接口时使用。创建 REST 或 GraphQL endpoint、定义模块之间的类型契约,或建立前后端边界时使用。
在真实浏览器中测试。构建或调试任何在浏览器中运行的内容时使用。当你需要通过 Chrome DevTools MCP 检查 DOM、捕获 console 错误、分析网络请求、分析性能,或用真实运行时数据验证视觉输出时使用。
自动化 CI/CD pipeline 设置。用于设置或修改构建和部署 pipeline 时;用于需要自动化质量门禁、在 CI 中配置 test runners,或建立部署策略时。
执行多维度代码审查。用于合并任何变更之前;用于审查自己、其他 agent 或人类编写的代码;用于在代码进入主分支前从多个维度评估代码质量。
为清晰度简化代码。用于在不改变行为的前提下重构代码以提升清晰度;用于代码能运行但比应有状态更难阅读、维护或扩展时;用于审查已累积不必要复杂度的代码时。
优化 agent 上下文设置。当开始新会话、agent 输出质量下降、在任务之间切换,或需要为项目配置规则文件和上下文时使用。
| name | deprecation-and-migration |
| description | 管理弃用和迁移。用于移除旧系统、API 或功能时;用于将用户从一种实现迁移到另一种实现时;用于判断应维护还是下线现有代码时。 |
代码是一种负债,而不是资产。每一行代码都有持续维护成本:需要修复 bug、更新依赖、应用安全补丁,并帮助新工程师理解它。弃用是一套移除不再值得维护的代码的纪律,迁移则是将用户安全地从旧系统转移到新系统的过程。
大多数工程组织都擅长构建东西,但很少擅长移除它们。这个 skill 就是为了弥补这个缺口。
每一行代码都有持续成本:它需要测试、文档、安全补丁、依赖更新,也会给附近工作的任何人带来理解成本。代码的价值在于它提供的功能,而不是代码本身。当同样的功能可以用更少的代码、更低的复杂度或更好的抽象来提供时,旧代码就应该离开。
只要用户足够多,每一种可观察行为都会被依赖,包括 bug、时序怪癖和未记录的副作用。这就是为什么弃用需要主动迁移,而不只是发公告。当用户依赖了替代方案没有复现的行为时,他们不能“直接切换”。
构建新东西时,要问:“三年后我们要如何移除它?”带有清晰接口、功能开关和最小表面积的系统,比到处泄漏实现细节的系统更容易弃用。
弃用任何东西之前,先回答这些问题:
1. Does this system still provide unique value?
→ If yes, maintain it. If no, proceed.
2. How many users/consumers depend on it?
→ Quantify the migration scope.
3. Does a replacement exist?
→ If no, build the replacement first. Don't deprecate without an alternative.
4. What's the migration cost for each consumer?
→ If trivially automated, do it. If manual and high-effort, weigh against maintenance cost.
5. What's the ongoing maintenance cost of NOT deprecating?
→ Security risk, engineer time, opportunity cost of complexity.
| 类型 | 何时使用 | 机制 |
|---|---|---|
| Advisory | 迁移是可选的,旧系统稳定 | 警告、文档、提示。用户按自己的节奏迁移。 |
| Compulsory | 旧系统有安全问题、阻碍进展,或维护成本不可持续 | 明确截止日期。旧系统将在日期 X 被移除。提供迁移工具。 |
默认使用建议弃用。 只有当维护成本或风险足以证明强制迁移合理时,才使用强制弃用。强制弃用要求提供迁移工具、文档和支持,不能只是宣布一个截止日期。
没有可用替代方案时不要弃用。替代方案必须:
## Deprecation Notice: OldService
**Status:** Deprecated as of 2025-03-01
**Replacement:** NewService (see migration guide below)
**Removal date:** Advisory — no hard deadline yet
**Reason:** OldService requires manual scaling and lacks observability.
NewService handles both automatically.
### Migration Guide
1. Replace `import { client } from 'old-service'` with `import { client } from 'new-service'`
2. Update configuration (see examples below)
3. Run the migration verification script: `npx migrate-check`
一次迁移一个消费者,不要一次性全部迁移。对每个消费者:
1. Identify all touchpoints with the deprecated system
2. Update to use the replacement
3. Verify behavior matches (tests, integration checks)
4. Remove references to the old system
5. Confirm no regressions
The Churn Rule: 如果你拥有正在弃用的基础设施,你就负责迁移你的用户,或者提供不需要迁移的向后兼容更新。不要宣布弃用后让用户自己摸索。
只有在所有消费者都完成迁移之后:
1. Verify zero active usage (metrics, logs, dependency analysis)
2. Remove the code
3. Remove associated tests, documentation, and configuration
4. Remove the deprecation notices
5. Celebrate — removing code is an achievement
并行运行新旧系统。将流量从旧系统逐步切到新系统。当旧系统承载 0% 流量时,移除它。
Phase 1: New system handles 0%, old handles 100%
Phase 2: New system handles 10% (canary)
Phase 3: New system handles 50%
Phase 4: New system handles 100%, old system idle
Phase 5: Remove old system
创建一个适配器,把旧接口调用转换到新实现。在迁移后端期间,消费者仍然使用旧接口。
// Adapter: old interface, new implementation
class LegacyTaskService implements OldTaskAPI {
constructor(private newService: NewTaskService) {}
// Old method signature, delegates to new implementation
getTask(id: number): OldTask {
const task = this.newService.findById(String(id));
return this.toOldFormat(task);
}
}
使用 feature flags 逐个将消费者从旧系统切换到新系统:
function getTaskService(userId: string): TaskService {
if (featureFlags.isEnabled('new-task-service', { userId })) {
return new NewTaskService();
}
return new LegacyTaskService();
}
Zombie code 指无人拥有但人人依赖的代码。它没有被主动维护,没有明确 owner,并会累积安全漏洞和兼容性问题。迹象包括:
应对方式: 要么指定 owner 并妥善维护,要么用具体迁移计划弃用它。Zombie code 不能一直悬而未决,它要么获得投入,要么被移除。
| 合理化借口 | 现实 |
|---|---|
| “它还能用,为什么要移除?” | 无人维护的可用代码会累积安全债和复杂度。维护成本会悄悄增长。 |
| “以后可能有人会需要它” | 如果以后需要,可以重建。为了“以防万一”保留未使用代码,成本通常高于重建。 |
| “迁移太贵了” | 把迁移成本和未来 2-3 年的持续维护成本比较。长期看,迁移通常更便宜。 |
| “等新系统完成后再弃用它” | 弃用规划从设计阶段开始。等新系统完成时,你会有新的优先级。现在就规划。 |
| “用户会自己迁移” | 他们不会。提供工具、文档和激励,或者自己完成迁移(The Churn Rule)。 |
| “我们可以无限期维护两个系统” | 两个系统做同一件事,意味着维护、测试、文档和 onboarding 成本都翻倍。 |
完成一次弃用后: