代码重构流程
代码重构流程
Section titled “代码重构流程”重构是程序员最爱的活,也是 AI 最容易翻车的活。
翻车的原因不是它不会改,而是它改着改着就改了行为。你让它把回调改成 async/await,它顺手把错误处理逻辑也「优化」了;你让它抽个函数,它顺便改了返回值。重构的重构是「在不改变外部行为的前提下改善内部结构」——这八个字,AI 不盯着就会跑偏。
下面这套流程,是让 Claude 老老实实做重构、不夹带私货的标准配方。
第一步:先 Plan,别急着改
Section titled “第一步:先 Plan,别急着改”重构的第一步不是写代码,是写计划。进 Plan Mode,把方案先定下来:
refactor the authentication module to use async/await instead of callbacks. don't change any behavior. plan firstplan first 这三个字让 Claude 进入「先想后做」模式:它会列出当前回调结构、目标 async/await 结构、每一步怎么动、每步如何验证,但不真的动文件。
Plan 出来之后,审计它。看看:
- 步骤是不是真的「小步」?(每步可独立验证)
- 有没有顺手夹带「优化逻辑」?(这就不是重构了)
- 测试如何介入?(每步跑测试还是只最后跑)
Plan 不满意,让它重做。Plan 阶段改方案零成本,落到代码上就贵了。
第二步:小步重构,每步测试
Section titled “第二步:小步重构,每步测试”Martin Fowler 在《重构》里讲的核心原则,在 AI 时代依然有效:小步走,每步绿。
execute step 1 of the refactor plan. run the test suite. if green, commit with message "refactor: step 1 - extract callback into async function". if red, /rewind and tell me what went wrong这种 prompt 把「一步」拆成五件事:执行、测试、判断、提交、回退。每一步都有出口,每一步都不让坏状态累积。
为什么不一次改完?因为重构一旦横跨多个文件、多轮 commit,出错的半径会指数放大。一步错,整个 diff 都得回退。小步走,最坏只回退一步。
第三步:用 review subagent 审查
Section titled “第三步:用 review subagent 审查”每完成一组重构,让一个独立上下文的 review 子代理审一遍:
delegate to the review subagent: examine the last 3 refactor commits. confirm no behavior change. flag any place where logic was altered, not just structure子代理的好处是它没看过你的对话历史——它只看代码本身,从外部视角判断「这是不是纯重构」。这比主代理自审更客观,因为它不会带着「我刚才为什么这么改」的偏见。
review 子代理返回的常见信号:
- 「这里把
try/catch改成了.catch(),行为等价但错误堆栈不同」——可能是行为变更。 - 「这里把同步函数改成了异步,调用方的执行时机变了」——肯定是行为变更。
- 「这个函数被抽出来,参数顺序变了」——API 变了,不是重构。
任何一条命中,立刻 /rewind 回到上一步,重新来。
第四步:/rewind 是你的安全网
Section titled “第四步:/rewind 是你的安全网”重构是 /rewind 用得最频繁的场景。因为重构是探索性的——你不知道这条路走得通走不通,得走了才知道。
/rewind 让你:
- 试错免费:走错路,啪啪两下 Esc 回到上个检查点。
- 多方案对比:方案 A 重构完跑一遍测试,rewind,方案 B 重构完跑一遍,对比哪个更干净。
- 回退对话也回退代码:rewind 选项里选「两者都」,回到那个时刻从头来。
不用 /rewind 的重构,相当于徒手攀岩——一失手就摔到下面,捡不回来。用了它,相当于系了安全绳——你可以放手尝试,反正绳子拽着。
区分重构 vs 行为变更:最重要的一条
Section titled “区分重构 vs 行为变更:最重要的一条”这一条单独拎出来,因为它是 AI 重构翻车的头号原因。
重构:在不改变外部行为的前提下,改善内部结构。 行为变更:改变了外部可观察的行为(输入相同但输出不同、错误处理不同、性能特性不同)。
AI 经常把这两件事混在一起做。比如你让它「抽个函数」,它顺手把「if x 改成 if x is not None」——逻辑更严谨了,但对 x = [] 这种边界,行为变了。
对抗方法:把「不允许行为变更」明确写进 prompt:
this is a pure refactor. do NOT:- change error handling logic- add or remove null checks- change the order of operations- "optimize" anythingif you spot a bug, flag it as a separate TODO. don't fix it inline.这条 prompt 把「夹带私货」的可能性几乎堵死。Claude 看到 bug,只能记 TODO,不能动手——这就是「重构就是重构」的纪律。
一个完整的重构 prompt 范例
Section titled “一个完整的重构 prompt 范例”Refactor target: src/auth/refresh.ts — convert from callback-based to async/await.
Plan first. The plan must:1. list every function to change, in dependency order2. specify how each step will be verified (which tests must pass)3. explicitly mark any behavior change as OUT OF SCOPE — flag it, don't fix it
Constraints:- public API signatures stay the same- error messages stay the same- no new dependencies
After each step:- run npm test- commit with conventional commit message "refactor(auth): step N - <what>"- if any test fails, /rewind and report
When done, delegate to the review subagent to verify no behavior change.填好这个模板,你的重构成功率会从「看运气」变成「大概率成」。
- 重构完想发 PR——看 创建 Pull Request。
- 想给重构加测试保护——读 编写测试。
- 重构遗留代码(更难的活)——去 重构遗留代码。
- /rewind 的完整用法——回顾 /rewind 安全绳。