用 AI 重构遗留代码,最稳妥的做法是:先让 AI 描述代码现在「实际在做什么」→ 用特征测试把这些行为锁住 → 让 AI 拆出一串可独立合并的小步骤 → 每次只执行一步并跑测试。 不要一次性让 AI「把这个文件重写得更优雅」,那几乎一定会悄悄改变行为。

场景

一个上千行的函数,没人敢动:里面混着数据库查询、业务规则和格式化输出,有些分支看起来像 bug,但可能有调用方依赖它。团队想把它拆开,又担心改出线上问题。

第一步:让 AI 描述现有行为

阅读下面的函数,不要修改代码。请输出:
1. 输入、输出与副作用(数据库写入、网络调用、日志、全局状态)
2. 所有分支及其触发条件(列表)
3. 看起来可疑但可能被依赖的行为(如异常被吞掉、特殊值处理)
4. 外部依赖清单
只描述代码实际行为,不要推测设计意图。
代码:……

开发者对照代码检查这份描述,标出不确定的地方,必要时查调用方。

第二步:补特征测试

特征测试(characterization test)记录代码当前的输出,不判断对错。

基于上面的行为描述,为该函数编写特征测试:
- 每个分支至少一个用例
- 断言当前实际输出(即使看起来不合理),并加注释「保持现状」
- 外部依赖用 mock 或测试替身
- 使用项目现有测试框架:……

运行测试,确保在未修改代码的情况下全部通过;不通过说明 AI 对行为的理解有误,回到第一步。

第三步:生成小步计划

目标:把该函数拆分为数据获取、业务规则、格式化三部分。
请给出重构步骤清单,要求:
- 每步都能独立提交并通过全部测试
- 每步只做一种变换(提取函数、重命名、移动、引入参数对象等)
- 标出风险较高的步骤和原因
- 前几步优先做纯机械、低风险的变换

第四步:逐步执行

每次只让 AI 执行一个步骤,生成 diff 后:

  1. 人工审阅 diff,确认只做了这一步承诺的变换。
  2. 运行全部测试。
  3. 提交,提交信息写清楚这一步做了什么。

可疑行为(第一步第 3 点)单独处理:先在 issue 中确认是否为 bug,再用独立的提交修复,不要混在重构里。

常见翻车点

  • 顺手修 bug:AI 发现「明显的错误」会自动修掉,导致行为改变。提示中明确「重构不改变行为」。
  • 步子太大:一个 diff 动几百行,审阅失效。
  • 测试也被改了:重构过程中特征测试不应修改,若 AI 改了测试要立刻警惕。
  • 忽略副作用:日志格式、异常类型也可能被下游依赖。

相关阅读