重构与迁移:大范围改动的护栏网
一句话定义
让 AI 执行大规模重构或迁移的前提是先张好护栏网——特征测试锁定行为、小批分片、每批可回滚、行为不变可验证——四件护栏缺一,批量修改就是在裸奔。
为什么重要
大规模重构(框架升级、API 迁移、目录重组)是 AI 的杠杆最大场景,也是事故最大场景:一次生成改 200 个文件,任何一个隐性错误都会混在批量 diff 里不可见。护栏网的意义是把「一次豪赌」变成「一百次可控小赌」:每批改动独立可验、可回滚,错误在最小批次内暴露。这是把 kp-013 审查工作流放大到批量场景的规模化版本。
前置知识
kp-012(TDD——特征测试的来源)、kp-013(Diff 审查流程)。
核心概念
- 特征测试(characterization test):在重构前对现有行为快照——不是测「应该怎样」而是测「现在怎样」。覆盖公共 API 输出、关键数据转换、边界输入。行为不变性由它证明。
- 小批分片:按文件/目录/依赖层次切片,每片一次 AI 会话、一个提交、独立可回滚。
- 行为不变验证:每批完成后跑特征测试 + 快照对比(序列化输出 diff),出现非预期差异即停。
- 禁改清单:生成代码、锁文件、部署脚本等不入批次的路径。
原理与机制
批量重构的核心风险是「行为漂移被批量噪声掩盖」:AI 在机械替换时会顺手「修正」它认为的 bug、统一它认为不一致的写法——这些善意改动正是事故源。机制上的对策:先快照(特征测试把当前行为固化为可执行断言),后批量(每批必须通过快照),差异即信号。分片的意义则是控制暴露面:单片 diff 小到可人审,问题单片回滚,定位成本从「200 个文件里找」降为「最后一批里找」。
实例或案例
操作步骤(一次库迁移的完整节奏):
- 盘点:让 AI 列出目标 API 的全部调用点(文件:行号),人抽查验证。
- 快照:为核心路径补特征测试(让 AI 起草、人审断言强度),当前状态全绿入库。
- 试点:选 1 个文件做迁移,全流程走通——AI 改、人审、测试、快照对比。
- 把试点发现写成批次规范(改名映射表、禁区、写法约定)进规则文件。
- 批量:按目录分 5-10 批,每批独立提交,节奏固定:生成 → 审 diff → 测试 → 快照 → commit。
- 收尾:清理废弃 shim、跑全量测试与集成验证,归档映射表。
重构提示模板(强调不变量):
任务:把 requests 调用迁移到 httpx(映射表见下)。
不变量:全部现有测试通过;超时/重试语义保持;不改任何业务逻辑。
范围:仅 pkg/a 与 pkg/b,禁止触碰 pkg/legacy。
输出:第一批只处理 pkg/a/core.py,产出 diff 等我确认后再继续下一文件。
映射:requests.get → httpx.get(注意 timeout 参数位置变化)……排错清单:
- AI「顺手修复」了旧 bug 导致快照失败 → 这是特性不是故障:在批次规范里写明「可疑处标记 TODO 提出来,禁止直接改」。
- 某批快照失败 → 立即回滚该批,修复规范后重跑该批,不带病前进。
- 批间风格不一致 → 映射表与写法约定没落盘,补规则文件再继续。
- 后期发现映射表有错 → 已完成批次逐批修正成本可承受——这正是小批分片的价值。
公式或模型
本节不适用:批次大小凭 diff 可审性经验确定(通常 ≤ 30 文件),无通用公式。
图示
盘点 → 特征测试(快照) → 试点批次 → 规范落盘 → 批量N批(生成→审→测→快照→commit) → 收尾
└──────────── 每批失败:回滚该批,不带病前进 ────────────┘直观类比
护栏网下的高空作业:不是保证你不失手,而是保证失手只掉一层脚手架的高度,且随时能爬回去重来。
常见误区
- 「AI 一次全改了更省事」:省下的是操作时间,赔上的是不可审的批量风险与不可定位的回滚。
- 跳过特征测试直接迁移:没有行为基准,「没坏」只是没人验证过。
- 把重构成纯机械替换:让 AI 顺手做「改进」——重构与优化必须分两个批次,各有各的验证。
与其他知识点的关系
kp-025 收录迁移中高频出现的错误模式;kp-016 的提交粒度规范决定回滚粒度。
自测题
要点:特征测试、小批分片、每批可回滚、行为不变验证。
要点:行为漂移混入批量 diff 无法审查,且破坏「行为不变」这一重构定义;应标记出来另立批次处理。
- 四件护栏是什么?
- AI 在迁移中「顺手修 bug」为什么必须禁止?
延伸阅读
《Refactoring(第2版)》Martin Fowler——特征测试与行为保持重构的原始方法论。