name: migrating-code description: 安全代码迁移,具有向后兼容性和可逆性。用于升级依赖、更改数据库模式、API版本控制或技术过渡。
代码迁移
核心原则
- 永不破坏生产 - 向后兼容直到完全推出
- 小、可逆的步骤 - 每个步骤独立可部署
- 在每个阶段测试 - 之前、期间和之后
- 随时准备回滚 - 总是
迁移清单
- [ ] 预迁移:阅读变更日志,识别破坏性更改,确保测试覆盖
- [ ] 期间:小步骤,测试每个,监控错误,准备回滚
- [ ] 后:验证测试,检查指标,移除脚手架,更新文档
数据库模式
安全模式
| 操作 | 模式 |
|---|---|
| 添加列 | 先添加可为空的列 → 回填 → 添加约束 |
| 移除列 | 停止写入 → 部署不读取的代码 → 删除列 |
| 重命名列 | 添加新列 → 双写 → 回填 → 切换读取 → 删除旧列 |
| 更改类型 | 新列 → 双写 → 批量迁移 → 切换 → 删除 |
绝不: 在没有默认值的情况下向有数据的表添加NOT NULL约束。
API迁移
弃用过程
- 向旧端点添加弃用警告
- 记录迁移路径
- 设置并沟通日落日期
- 监控使用情况
- 使用量下降后移除
{
"data": {},
"_warnings": [{
"code": "DEPRECATED_ENDPOINT",
"message": "使用 /api/v2/users 代替",
"sunset": "2025-06-01"
}]
}
框架升级
- 先升级到最新次要版本 - 获取弃用警告
- 修复警告 - 在大版本升级之前
- 一次只升级一个主要版本 - 不要批量
- 每个步骤后测试
用于库交换的适配器模式
// 包装库使用
// lib/date.ts
import moment from 'moment';
export const formatDate = (date: Date, format: string) =>
moment(date).format(format);
// 迁移:只需更改适配器
import { format } from 'date-fns';
export const formatDate = (date: Date, fmt: string) =>
format(date, fmt);
逐步推出
使用功能标志:
if (featureFlags.useNewSystem) {
return newService.process(order);
} else {
return legacyService.process(order);
}
推出:1% → 10% → 50% → 100% → 移除标志
常见陷阱
避免:
- 大爆炸式迁移
- 没有回滚计划
- 跳过双写阶段
- 单个大数据事务
- 在新代码被证明之前移除旧代码
做:
- 小、可逆的步骤
- 测试回滚程序
- 批量大数据迁移
- 保持旧路径直到新路径被验证