Skip to content

用 Codex 做可回退的重构与迁移

重构的风险不在于改动行数,而在于“行为保持不变”很难证明。让 Codex 一次性搬完整个模块,往往会把结构变化、行为变化和顺手优化混在一起。本章用分阶段迁移把风险变成可以逐步验证的差异。

先定义“不变”和“允许变化”

示例:

text
目标:拆分 auth 模块中的令牌解析、会话加载和权限判断,消除循环依赖并提高可测试性。

必须保持:
- 所有公开接口、错误码和响应结构;
- 登录态过期和刷新行为;
- 现有数据库结构;
- 线上配置字段名称。

允许变化:
- 内部目录和私有类型;
- 模块依赖方向;
- 测试组织。

不在范围:
- 更换认证方案;
- 升级框架;
- 修改 UI;
- 性能优化。

边界越清楚,Codex越不容易把重构变成重写。

第一步:建立行为基线

要求 Codex找出现有保护网:

text
先只读分析 auth 模块。列出公开入口、调用方、状态变化、错误类型、配置字段、数据库访问和现有测试。找出行为没有测试保护的区域,并提出最小特征测试,不要开始重构。

对关键行为补“特征测试”:不评价现状是否优雅,只固定当前外部行为,以便后续发现意外变化。

第二步:画依赖与迁移地图

输出至少包含:

  • 当前模块依赖图;
  • 目标模块边界;
  • 每个调用方迁移顺序;
  • 临时适配层;
  • 可删除旧代码的条件;
  • 每个阶段的回滚点。

提示:

text
把迁移拆成最多 5 个阶段。每个阶段必须能独立构建和测试,说明修改文件、兼容策略、验证命令和回退方式。不要在同一阶段同时迁移所有调用方并删除旧入口。

第三步:先建立新边界,不迁移行为

第一阶段通常只做:

  • 新建接口或内部模块;
  • 把旧实现包在兼容层后面;
  • 增加契约测试;
  • 保持所有调用方不变。

如果这一步已经改变用户行为,切片仍然太大。

第四步:逐个调用方迁移

text
只迁移调用方 [名称/目录] 到新边界。其他调用方继续走兼容层。完成后运行该调用方测试、auth 模块测试和类型检查,并比较公开行为。

每迁移一批都检查 Git diff。必要时用独立 worktree 处理不同但不重叠的调用方,禁止多个任务同时编辑同一核心文件。

第五步:处理数据库和公共 API 迁移

需要改变数据或接口时,不再是纯重构,应单独设计兼容方案:

  • 先加后删;
  • 旧字段继续可读;
  • 写入幂等;
  • 迁移脚本可重复或能检测已执行;
  • 有回滚脚本或备份;
  • 新旧版本可在发布窗口内共存;
  • 通过指标确认旧路径已无流量。

不要让 Codex只根据代码搜索结果判断“旧字段已经没人用”。还要检查报表、脚本、外部客户端和线上流量。

第六步:最后删除兼容层

只有满足以下条件才删除旧代码:

  • 所有内部调用方已迁移;
  • 外部兼容期结束;
  • 完整测试和构建通过;
  • 日志或指标显示旧入口无使用;
  • 文档和配置已经更新;
  • 回滚策略不再依赖旧实现。

删除阶段单独提交最容易审查,不要与核心迁移混在一起。

使用 Codex 云任务或 Subagents 的边界

适合并行的工作:独立调用方迁移、测试补充、文档更新、静态引用盘点。

不适合无约束并行的工作:核心接口设计、同一迁移脚本、同一公共类型、会产生冲突的格式化。

并行前明确:文件所有权、基线分支、接口版本和合并顺序。

验证阶梯

每个阶段至少运行:

  1. 新增契约/特征测试;
  2. 当前模块测试;
  3. 已迁移调用方测试;
  4. 类型检查或编译;
  5. 跨模块集成测试;
  6. 完整构建;
  7. 关键用户路径;
  8. 公开 API 或数据差异检查。

常见失败

重构中顺便修业务

把行为修复拆成独立任务,否则出现回归时无法判断来源。

计划只有文件列表

文件列表不说明迁移顺序和兼容性。要求每阶段都能独立运行。

过早删除旧入口

先迁移并观测,再删除。代码搜索不是唯一使用证据。

测试也被一起重写

至少保留一层从用户或公开接口角度验证行为的独立测试,避免实现和测试一起“自洽地变错”。

完成报告模板

text
保持不变的行为:[列表]
迁移阶段:[完成/未完成]
当前兼容层:[位置和删除条件]
验证结果:[命令和结果]
仍在使用旧路径的调用方:[列表]
回滚点:[分支/提交/开关或明确步骤]

下一步

重构完成后用 代码审查、Git 与 PR 闭环 检查差异。如果需要并行代理,继续学习 Subagents 实战

程序员小枫同学:用好新工具,练好工程内功,做出可靠交付。