>
每一次失败的迁移都有相同的讣告:我们试图一次性替换所有东西,进行到一半时时间不够了,现在我们有两个系统。
你需要进行迁移。可能是 Express → Fastify。可能是 JavaScript → TypeScript。可能是 MySQL → PostgreSQL。可能是 React 类组件 → hooks。可能是单体架构 → 微服务。
你知道当前的位置。你知道目标位置。你不知道两者之间的安全路径——那种能让你增量变更、每一步都能验证、出问题时可以回滚,同时保持生产环境正常运行的顺序。
迁移指南针会生成这条路径。
无论迁移什么,每一次迁移都遵循相同的基本结构:
状态A(当前)────── 过渡阶段 ────── 状态B(目标)
│
├── 并行运行区(两种状态共存)
├── 回滚点(安全的回退位置)
├── 验证关卡(证明每一步都有效)
└── 绞杀边界(旧接口 → 新接口)
法则一:绝不一次性大爆炸
一次只改变一件事。验证。继续或回滚。需要同时改变一切的迁移不是迁移——那是伪装成迁移的重写。
法则二:替换前先并行
新系统在替换旧系统之前必须与旧系统并行运行。在移除旧系统之前,你需要证明新系统在生产环境中能正常工作。
法则三:每一步都必须可部署
在迁移过程中,代码库在任何时候都不能处于无法部署到生产环境的状态。每一次提交都是一个有效的检查点。
示例:moment.js → date-fns
指南针路线:
├── 第一步:审计
│ ├── 查找所有 moment 的导入(grep 分析)
│ ├── 记录你使用的所有 moment 函数
│ ├── 将每个 moment 函数映射到 date-fns 的等价函数
│ └── 识别没有 date-fns 等价函数的 moment 特性
│
├── 第二步:并行安装
│ ├── npm install date-fns(与 moment 并行,不替换)
│ ├── 创建适配器模块:src/utils/date-adapter.ts
│ │ └── 导出你的日期操作,内部调用 moment 或 date-fns
│ └── ✅ 部署。两个库都已安装。仅使用 moment。
│
├── 第三步:迁移消费者(一次一个)
│ ├── 将导入从 moment 改为从 date-adapter 导入
│ ├── 不要改变行为——适配器内部调用 moment
│ ├── ✅ 每次文件后部署。回滚 = 还原一个文件。
│ └── 重复直到所有消费者都使用适配器
│
├── 第四步:交换内部实现
│ ├── 在 date-adapter 内部,将实现从 moment 改为 date-fns
│ ├── 运行测试。比较输出。
│ ├── ✅ 部署。如有问题,仅还原适配器内部(一个文件)。
│ └── 监控边界情况(时区、区域设置、格式化)
│
├── 第五步:清理
│ ├── 从 package.json 中移除 moment
│ ├── 可选择内联适配器(或保留以备将来灵活性)
│ ├── ✅ 部署。
│ └── 总迁移:N 个小 PR,零停机,每一步都可完全回滚
│
└── 回滚点:每一步。最大回滚成本:还原 1 个文件。
示例:Express → Fastify
指南针路线:
├── 第一步:审计
│ ├── 记录所有路由(数量、复杂度、中间件使用情况)
│ ├── 记录所有中间件(认证、日志记录、CORS 等)
│ ├── 识别 Express 特有的模式(req/res 增强等)
│ └── 将 Express 概念映射到 Fastify 等价概念
│
├── 第二步:绞杀外观
│ ├── 在 Express 前面引入反向代理(或路由分发器)
│ ├── 所有流量 → Express(行为无变化)
│ ├── ✅ 部署。验证无变化。
│ └── 该代理稍后将把流量分发到 Express 和 Fastify 之间
│
├── 第三步:并行实例
│ ├── 在 Express 旁边启动 Fastify 实例
│ ├── 迁移一个低风险路由(健康检查、静态资源等)
│ ├── 路由代理:/health → Fastify,其他所有 → Express
│ ├── ✅ 部署。验证 Fastify 正确提供 /health 服务。
│ └── 回滚:将 /health 路由回 Express
│
├── 第四步:增量路由迁移
│ ├── 一次迁移一个路由(或小批量)
│ ├── 顺序:最低风险 → 最高风险
│ │ ├── 静态路由(无状态、无认证)
│ │ ├── 只读认证路由
│ │ ├── 写入路由(变更操作)
│ │ └── 复杂路由(多步骤、事务性)
│ ├── 对于每个路由:
│ │ ├── 在 Fastify 中实现
│ │ ├── 通过并行运行验证(相同请求 → 两个系统 → 比较)
│ │ ├── 将代理切换到 Fastify
│ │ ├── ✅ 部署。监控。
│ │ └── 回滚:将代理切换回 Express
│ └── 重复直到所有路由都在 Fastify 上
│
├── 第五步:退役
│ ├── 从 package.json 中移除 Express
│ ├── 移除代理(Fastify 直接提供服务)
│ ├── ✅ 部署。
│ └── 清理任何兼容性垫片
│
└── 回滚点:按路由。最大回滚:重新路由一个端点。
示例:JavaScript → TypeScript
指南针路线:
├── 第一步:配置
│ ├── 添加 tsconfig.json,设置 strict: false(宽松启动)
│ ├── 启用 allowJs: true(JS 和 TS 共存)
│ ├── ✅ 部署。零行为变化。
│
├── 第二步:重命名(先处理叶子节点)
│ ├── 依赖图:找到没有导入者的文件(叶子节点)
│ ├── 将 .js 重命名为 .ts(一次一个文件)
│ ├── 添加最小类型(编译需要的地方用 any)
│ ├── ✅ 每批处理后部署。
│ └── 向内推进:叶子 → 分支 → 主干
│
├── 第三步:收紧
│ ├── 用真实类型替换 any(一次一个模块)
│ ├── 增量启用更严格的 tsconfig 规则:
│ │ ├── noImplicitAny
│ │ ├── strictNullChecks
│ │ ├── strictFunctionTypes
│ │ └── strict: true(最终)
│ ├── ✅ 每次规则变更后部署。
│ └── 回滚:禁用该规则,稍后修复
│
├── 第四步:清理
│ ├── 当所有文件都是 .ts 时移除 allowJs
│ ├── 移除所有剩余的 @ts-ignore 注释
│ └── ✅ 部署。
│
└── 回滚点:重命名时按文件。收紧时按规则。
输入:从什么迁移?迁移到什么?当前使用情况如何?
第一阶段:调研
├── 分析源系统的当前使用情况(哪些功能、哪些模式)
├── 将源概念映射到目标等价概念
├── 识别差距(没有目标等价概念的源功能)
├── 估算每个组件的迁移工作量
└── 识别风险最高的组件(最复杂、最关键)
第二阶段:路线规划
├── 确定迁移类型(库、框架、语言、数据库、架构)
├── 选择迁移策略:
│ ├── 绞杀藤模式:按路由替换(最适合服务)
│ ├── 通过抽象分支:适配器层交换(最适合库)
│ ├── 并行运行:两个系统同时运行(最适合数据存储)
│ └── 增量重写:逐文件转换(最适合语言)
├── 组件排序:最低风险优先 → 最高
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 migration-compass-1776235689 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 migration-compass-1776235689 技能
skillhub install migration-compass-1776235689
文件大小: 5.21 KB | 发布时间: 2026-4-15 23:58