# Maintain Team Deprecation Migration

> 弃用与迁移——管理代码生命周期。当需要移除、替换或迁移已有功能/API，或提到"弃用""迁移""deprecation""breaking change"

- Skill: `zeroz-lab/maintain-team-deprecation-migration` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zeroz-lab/maintain-team-deprecation-migration`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zeroz-lab/maintain-team-deprecation-migration/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: zeroz-lab (https://skillmd.com/u/zeroz-lab)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zeroz-lab/maintain-team-deprecation-migration

---


# Deprecation & Migration — 弃用与迁移


## 入口/出口
- **入口**: 需要移除或替换已有功能、API 版本升级、清理废弃代码
- **出口**: 迁移计划 + 兼容层（如需要）+ 文档 + 清理
- **指向**: 迁移完成后回到正常 build 流程
- **前置加载**: CANON.md
- **输出路径**: verify-workflow-review

## 何时不使用
- 只是新增功能，不移除、替换或改变已有行为
- 废弃范围没有使用数据、兼容要求或迁移窗口
- 只是删除本任务中新建且尚未发布的临时代码

## 核心原则

### Code Is a Liability
**代码是负债，不是资产。** 未使用的代码仍然需要维护、编译、测试、理解。每行代码都有持续成本。删除代码是改善。

### Hyrum 法则使删除困难
**有足够用户时，每个可观察到的行为都有人依赖。** 即使是未文档化的实现细节、错误消息文本、响应字段排序——某处可能有消费者依赖它。

### 弃用规划从设计时开始
设计 API 时就为未来弃用规划——使用 Feature Flag 或版本化参数，使旧行为可逐步下线。

## 弃用决策

在宣布弃用之前回答：

1. **有替代方案吗？** 用户迁移到哪里？替代至少和旧方案一样好。
2. **还有多少用户？** 多少人依赖这个 API/功能？实际使用量是多少？
3. **迁移成本被承担了吗？** 谁负责迁移——提供者还是消费者？迁移工具和文档存在吗？
4. **时间线合理吗？** 如果消费者团队需要 6 个月，不给他们 2 周。
5. **紧急回退可能吗？** 如果迁移出问题，可以立即恢复弃用功能吗？

## 强制 vs 必须弃用

| 类型 | 机制 | 适用 |
|------|------|------|
| **强制弃用** | 弃用日期后功能移除。消费者必须迁移。 | 安全修复、无法维护的旧系统 |
| **必须弃用** | 功能可用但文档化和告警说明即将移除。消费者有时间迁移。 | 改进但不紧急 |

**"必须弃用"不是永久的。** 如果消费者不迁移，"建议"变为"强制"带日期。

## 迁移模式

### Strangler Pattern（最安全）

```
新系统逐步接管旧系统功能:
  Phase 1: 新系统 + 旧系统并存（新代码走新路径）
  Phase 2: 逐渐迁移旧路径到新系统
  Phase 3: 旧系统仅剩 5% 流量
  Phase 4: 旧系统完全关闭

不一次性替换。一条条路由/功能逐步迁移。
```

### Adapter Pattern

```typescript
// 消费者调用 v2 API → v2 handler（当前版本）
// 旧消费者仍调用 v1 API → v1 adapter → 转换请求 → 委托给 v2 handler
// 所有 v1 消费者迁移后 → 删除 v1 adapter
async function v1CreateTaskHandler(req: V1Request): Promise<V1Response> {
  const v2Request = toV2Request(req);      // v1 → v2 转换
  const v2Response = await v2Handler(v2Request);
  return toV1Response(v2Response);          // v2 → v1 转换
}
```

### Feature Flag 迁移

```typescript
// Flag 控制新旧代码路径
if (await featureFlag.isEnabled('use-new-task-service', userId)) {
  return newTaskService.create(req);  // 新路径
} else {
  return oldTaskService.create(req);  // 旧路径（逐步关闭 flag）
}
```

## 迁移决策流程图

```
需要弃用？
  ├── 突发弃用（安全漏洞、合规要求）
  │   └── 立即下线 + 紧急通知消费者
  └── 渐进弃用
      ├── 多个消费者？
      │   ├── YES → Strangler Pattern（逐个迁移）
      │   └── NO → Adapter 或直接替换
      ├── 需要兼容期？
      │   ├── YES → Feature Flag 控制新旧路径
      │   └── NO → 直接替换 + 版本号大版本升级
      └── 通知 → 设置过期 → 监控使用 → 移除旧代码
```

## 反模式修复表

| 反模式 | 问题 | 修复 |
|--------|------|------|
| 只在注释里写 `@deprecated` | 没人看注释，消费者无感知 | 加上 `console.warn` / 运行时警告 + 使用量监控 |
| 没有度量就删除代码 | 可能还有人在用，删除即事故 | 先加埋点追踪使用量，确认为零后再删 |
| 新代码还在依赖废弃 API | 弃用形同虚设，永远无法清理 | CI 规则禁止新代码引入废弃 API import |
| 没有通知消费者就下线 | 消费者突然崩溃，生产事故 | 最少 2 个版本的弃用公告期 |
| 迁移中途停止（旧新并存） | 两套系统永久并存，复杂度翻倍 | 设死线，到期未迁的由平台强制切换 |
| 废弃了但忘了清理 | 僵尸代码堆积，拖累系统 | 每个废弃有 owner + 过期日期，过期后自动创建清理 PR |
| 替代方案质量低于旧方案 | 消费者拒绝迁移，两套永久并存 | 替代至少和旧方案一样好。不够好就不废弃。 |
| 弃用公告没有迁移指南 | 消费者不知道怎么改，只能拖着 | 每条弃用公告附带迁移示例和文档链接 |

## 好/坏弃用公告对照

```typescript
// Bad: 仅注释——无人感知
// @deprecated use newUserService instead
export const oldGetUser = ...

// Good: 运行时警告 + 迁移指引 + 截止日期
export const oldGetUser = (id: string) => {
  console.warn(
    '[DEPRECATED] oldGetUser will be removed in v3.0 (2026-06-01). ' +
    'Migrate to: userService.getUser(id) — see docs/migration/v2-to-v3.md'
  );
  trackDeprecatedUsage('oldGetUser');
  return userService.getUser(id);
};
```

**好弃用公告三要素：**
1. **运行时警告** — 每次调用时提醒消费者，不是沉默的注释
2. **迁移指引** — 明确告诉消费者改用什么、怎么改、文档在哪
3. **截止日期** — 给出具体移除时间，不是"未来某天"

## Zombie Code 定义

代码是僵尸代码当它：
- 无人维护，但仍在运行
- 有活跃消费者，但 owner 已经离职/转组
- 文档缺失，但行为有人依赖
- 技术上已弃用，但关闭日期无限期推迟

**僵尸代码必须消灭。** 标注 owner、迁移消费者、设定关闭日期。

## 常见说辞

| 说辞 | 现实 | 后果 |
|------|------|------|
| "先留着吧，以后可能有用" | 留着 = 维护+测试+编译+理解成本。YAGNI（你不会需要它）。 | 僵尸代码堆积，每行年维护成本 ≥ 1h，团队理解成本随代码量线性增长 |
| "没人用的代码不用管" | 你怎么知道没人用？在关闭前加日志/指标验证。 | 未验证删除导致生产事故，修复时间 ≥ 2h + 影响所有未知消费者 |
| "直接删就行" | Hyrum 法则。某处有东西依赖它。总是用弃用→兼容→清理的三步过程。 | 跳过弃用流程直接删除，依赖方突然崩溃，紧急回滚 ≥ hotfix + 全量回归测试 |
| "必须弃用就够，消费者会自己迁移" | 很少消费者主动迁移。需要明确关闭日期 + 多次通信 + 迁移支持。 | 消费者不迁移导致双系统永久并存，维护成本翻倍 ≥ 2x |
| "没人用那个 API" | 你确定？查监控数据，不猜。 | 猜测代替数据导致误删，生产故障影响 ≥ 所有依赖该 API 的服务 |
| "新 API 还没准备好，先保留旧的" | 那不叫废弃，叫双写。设时间线。 | 无时间线的双写永远并存，技术债务累积 ≥ N 个未关闭的弃用项 |
| "文档更新等删代码时一起做" | 文档先行。消费者需要迁移指南才能迁移。 | 无迁移指南消费者无法行动，弃用周期延长 ≥ 2-3 个版本 |
| "废弃太麻烦了，直接改" | Breaking change 不走废弃流程 = 生产事故。 | 未走流程的 breaking change 导致下游团队生产故障，影响 ≥ M 个消费方 |
| "这个 API 只有我们内部用" | 内部团队也是消费者。内部依赖断裂同样导致生产故障。 | 内部依赖断裂影响 ≥ N 个内部服务，排查时间 ≥ 跨团队协调 1 周 |
| "消费者还没迁移，再延长一下" | 延期一次可以，延期两次说明你的迁移支持不够。主动提供协助。 | 反复延期导致弃用信誉下降，后续弃用更难推进，周期 ≥ 延期 N 次 |

## 红旗 — STOP

- 弃用公告中没有指定替代方案
- 弃用时间线给消费者不合理的短时间（< 1 个迭代）
- 弃用功能被新功能继续调用（"先弃用，然后我们自己也用它"）
- Comments-only 弃用（"// deprecated" 但没日志、没告警、没文档）
- 旧代码直接删除——没有任何兼容期

## 验证失败处理

| 失败场景 | 处理方式 |
|---------|---------|
| 消费者拒绝迁移 | 评估影响范围。如影响小可强制下线；如影响大需升级到管理层决策。 |
| 迁移引入新 bug | 回滚到旧路径，调查根因，修复后重新迁移。不要在旧路径有 bug 时继续。 |
| 回滚失败（旧代码已删除） | 从 git 历史恢复旧代码作为 hotfix，重新评估迁移策略。保留旧代码直到确认新路径稳定。 |
| 替代方案本身也需要废弃 | 质疑架构方向。暂停迁移，重新评估替代方案。废弃链说明设计有问题。 |
| 依赖链式废弃（A→B→C） | 从叶子节点开始逐个迁移，不要并行。画出依赖图，按拓扑排序执行。 |
| 使用量降为零但仍有调用报错 | 检查监控覆盖是否完整。可能有未接入监控的调用方。加全链路追踪确认。 |

## 人类伙伴信号

**以下话语出现时，说明你的弃用流程有缺口：**

- **"这个 API 什么时候下线？"** — 你没设过期日期。每条弃用公告必须有明确截止时间。
- **"还有谁在用这个？"** — 你没追踪使用量。废弃前必须加监控，数据驱动决策。
- **"迁移指南在哪？"** — 你没写迁移文档。文档先行，消费者需要指南才能行动。
- **"能再宽限几天吗？"** — 你的时间线太紧了。重新评估消费者迁移节奏，调整截止日期。
- **"我用了新 API 但行为不一样"** — 你的替代方案没有完全覆盖旧 API 的行为。补充测试用例对齐。
- **"为什么线上还在调旧接口？"** — 你的监控没覆盖所有消费者，或弃用通知没到达。加运行时警告。

**全部意味着：STOP。回到弃用决策，补齐缺失环节。**

## 输出模板

弃用与迁移完成后应产出以下结构（记录于 ADR 或项目文档中）：

```markdown
### Deprecation & Migration 记录

**弃用目标**: [API / 功能 / 模块名]
**替代方案**: [新 API / 新功能名 + 迁移路径]
**弃用类型**: [强制 / 必须]
**截止日期**: [YYYY-MM-DD]

**消费者影响评估**:
| 消费者 | 当前调用量 | 迁移状态 | 迁移支持 |
|--------|-----------|----------|----------|
| [团队/服务1] | [N 次/天] | [已迁移 / 未迁移 / 迁移中] | [迁移指南 / 工具 / 无] |

**迁移时间线**:
- Phase 1: [YYYY-MM-DD] — 新旧并存，运行时警告上线
- Phase 2: [YYYY-MM-DD] — 使用量监控确认下降
- Phase 3: [YYYY-MM-DD] — 旧代码关闭/删除

**回退计划**: [hotfix 路径 / feature flag 回退 / git revert 策略]
**已知限制**: [兼容层行为差异 / 监控覆盖缺口 / 未迁移消费者]
```

## 验证清单

- [ ] 替代方案明确且可用（消费者迁移到此）
- [ ] 弃用时间线合理（执行了消费者迁移节奏）
- [ ] 实际使用量已验证（日志/指标——不只是猜测）
- [ ] 消费者已通知（文档、公告、直接联系）
- [ ] 回退计划存在（如果迁移出问题）
- [ ] 旧代码清理已完成（compat layer → 删除 → ADR 标记为"废弃"）

