重构最怕的不是代码改得多,而是改完以后说不清楚行为有没有变化。AI 工具能很快移动代码、抽函数、改命名、补类型,但如果缺少边界和验证,大规模重构很容易从“改善结构”变成“引入不确定性”。
更稳妥的做法,是把 AI 当成一个执行力很强的工程助手,让它在明确目标、有限范围和可重复验证的约束下工作。重构不应该一次性追求“变得优雅”,而应该被拆成一组可以审查、可以回滚、可以证明行为不变的小步骤。
一、先判断是不是应该重构
不是所有看起来不舒服的代码都值得马上重构。重构应该服务于具体目标,而不是单纯追求形式整洁。
比较值得启动重构的场景包括:
- 同一段业务规则在多个位置重复出现。
- 一个函数同时负责校验、计算、存储和展示。
- 新需求每次都要改很多无关文件。
- 异常路径散落在调用链里,问题难以定位。
- 测试很难编写,因为逻辑和外部依赖耦合太紧。
- 命名和模块边界已经无法表达真实业务含义。
如果只是局部命名不喜欢,或者短期不会继续演进,重构的收益可能不够高。AI 让修改成本下降了,但 review、测试和回归风险并不会自动消失。
二、给 AI 一个明确的重构目标
“帮我重构这段代码”太宽泛,AI 很容易顺手做过头。更好的任务描述应该包含目标、范围和禁止事项。
例如:
1 | 请只重构订单金额计算逻辑。 |
这类说明会让 AI 知道什么可以动,什么不能动。尤其是“保持外部接口不变”很重要,它能把任务限制在内部结构调整,而不是演变成一次行为变更。
如果重构涉及多个模块,可以进一步要求分阶段:
1 | 第一步只提取纯函数,不改变调用方。 |
AI 很适合执行这种机械但需要细心的步骤。人负责判断方向,AI 负责把小步骤做完整。
三、先建立行为保护网
重构的核心原则是:结构可以变,行为不能无意变化。要做到这一点,最好在动代码之前先有保护网。
保护网不一定一开始就很完整,但至少要覆盖最关键的业务假设:
- 正常输入得到稳定结果。
- 空值、非法值和边界值不会导致崩溃。
- 失败路径返回可预期错误。
- 重复调用不会产生额外副作用。
- 对外接口的响应结构不变化。
对于纯逻辑代码,优先补单元测试。对于 Android 项目,可以先覆盖 ViewModel、Repository、格式化器、状态转换等不依赖 UI 的部分。对于后端服务,可以覆盖参数解析、权限判断、幂等逻辑和错误码。
如果当前代码很难测试,也不要一上来大拆。可以先加几条高价值的黑盒测试,固定住外部行为,然后再逐步把内部逻辑抽出来。
四、每次只改一种事情
重构最容易失控的地方,是在同一个提交里混合太多类型的变化。
常见的混合包括:
- 改命名的同时改业务逻辑。
- 移动文件的同时升级依赖。
- 抽象公共模块的同时改接口返回值。
- 格式化全文件的同时修 bug。
- 删除旧代码的同时替换调用链。
这些改动放在一起,review 会变得很痛苦。审查者很难判断某一行变化到底是行为修复、结构调整,还是格式化带来的噪音。
更稳的拆法是:
- 先补测试,证明当前行为。
- 再做纯移动、纯命名、纯提取函数这类机械改动。
- 然后替换调用方。
- 最后删除旧实现。
每一步都应该能独立构建或通过测试。如果其中一步出问题,也更容易回滚。
五、让 AI 输出可审查的 diff
AI 一次性改太多文件时,最重要的不是它“看起来完成了”,而是 diff 是否容易审查。
可以在任务里明确要求:
1 | 请控制单次改动范围。 |
完成后还可以让 AI 自查一次:
1 | 请检查这次 diff 是否存在无关改动。 |
这一步的价值在于把“代码变化”翻译成“工程意图”。如果 AI 自己都无法清楚说明某个文件为什么被改动,通常说明这部分变化需要重新拆分。
六、处理遗留代码要先隔离副作用
遗留代码难重构,通常不是因为语法复杂,而是因为副作用太多。一个函数里可能同时读配置、访问数据库、发网络请求、写日志、更新 UI 状态。
面对这种代码,第一步不是直接抽象接口,而是先识别副作用边界:
- 哪些输入来自外部环境。
- 哪些输出会改变持久化数据。
- 哪些调用可能失败或超时。
- 哪些状态依赖调用顺序。
- 哪些逻辑可以变成纯函数。
可以先让 AI 只做分析,不做修改:
1 | 请阅读这个模块,列出纯计算逻辑和外部副作用。 |
等边界清楚后,再让它做最小提取。比如把金额计算、状态判断、文本格式化先抽出来,数据库和网络访问仍然留在原位置。这样风险会小很多。
七、命名重构要保持业务语义
AI 很擅长批量改名,但命名不是单纯把变量变长。好的命名应该表达业务语义,而不是只描述技术形状。
例如:
1 | data -> orderSummary |
命名重构时要注意两点:
- 不要把领域概念改成模糊的技术词。
- 不要为了统一风格破坏已有公共 API。
如果命名会影响序列化字段、数据库列、路由参数、前端埋点或第三方协议,就不能当作普通变量重命名处理。AI 批量替换前,必须先确认这些边界。
八、验证不只跑一次
重构后的验证应该分层,而不是只在最后跑一次构建。
比较实用的节奏是:
1 | 小步骤完成后:运行相关单元测试。 |
对于博客、前端或脚本项目,构建命令就是最低要求。对于应用项目,还要结合单元测试、静态检查、打包和关键页面手动验证。
如果某些验证因为环境缺失无法执行,结果说明里要写清楚:
1 | 已运行 npm run build,通过。 |
这比一句“应该没问题”可靠得多。
九、保留回滚路径
好的重构应该能被回滚。不是说一定会失败,而是要避免把风险绑死在一个巨大提交里。
可以用几种方式保留回滚空间:
- 分多次提交,每次只做一种变化。
- 保持旧接口一段时间,先让新实现并行接入。
- 对高风险路径加开关或灰度条件。
- 删除旧实现前确认调用方已经全部迁移。
- 在变更说明里写清楚验证范围和风险点。
AI 可以帮助生成迁移清单,但最终仍然要由维护者判断是否可以删除旧逻辑。尤其是被反射、配置、脚本或第三方调用的代码,不能只靠静态搜索下结论。
十、一个可复用的重构提示词
日常可以把下面这段作为起点:
1 | 请以小步重构方式处理这个模块。 |
这段提示词的重点不是让 AI 变得保守,而是让它把重构当成工程交付,而不是代码美化。
十一、总结
AI 让重构的执行速度变快,但重构的本质没有变:先理解行为,再改善结构,最后用验证证明没有引入意外变化。
真正可靠的 AI 辅助重构,应该具备三个特征:
- 目标明确,知道为什么改。
- 步骤足够小,每一步都能审查。
- 验证可重复,结果能被复盘。
当重构被拆成可验证的小步骤后,AI 的优势会非常明显。它可以承担大量重复、细碎、容易疲劳的修改工作,而开发者把注意力放在边界、风险和设计判断上。这样的协作方式,才更适合长期维护的真实项目。
- 本文链接: https://blog.hansong.icu/2026/06/27/AI_Refactoring_Workflow_2026_06_27/
- 版权声明: 本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。