开发提效

AI 遗留代码重构:先建护栏,再小步替换

文章目录 / 点击展开

遗留代码重构最危险的起点,是让 AI “把这段代码优化一下”。当现有行为、依赖和异常路径还不清楚时,漂亮的重写很可能悄悄改变业务。更稳妥的流程是先记录当前行为,建立测试护栏,再让 AI 提出范围受限、可以验证和回滚的小步改动。

先定义这次重构不改变什么

写清本次允许修改的模块、必须保持的接口、性能或兼容性约束、不可触碰的数据迁移和发布窗口。把“提升可维护性”翻译成可检查目标,例如拆出重复校验、降低单个函数职责、补齐测试或隔离第三方调用。

如果需求包含功能新增、数据库迁移和框架升级,应分开规划。把多个高风险变化绑在同一次重构里,会让问题很难定位。

第一步:画出真实运行路径

从入口请求、定时任务或消息消费者开始,追踪到核心业务、数据库、缓存、外部服务和日志。记录输入来源、关键状态、异常处理、权限校验和副作用。AI 适合根据仓库搜索结果整理调用图,但每条路径都要能回到具体文件和测试。

根据以下文件列表和调用片段整理当前行为。
输出入口、调用链、外部依赖、读写数据、副作用、异常路径与未知项。
不要提议修改代码;先列出需要验证的假设和对应证据。

对陌生仓库的初步梳理可参考 Claude Code 代码库分析教程

第二步:将现有行为变成测试护栏

先为最重要的正常流程、边界输入、失败路径和外部调用行为写测试。对于难以直接测试的旧代码,可以先用特征测试记录当前输出、状态变化和副作用,再逐步改善结构。

测试不是为了证明旧实现优雅,而是为了发现重构是否改变了约定。需要特别覆盖空值、重复请求、权限不足、超时、并发和历史兼容输入。单元测试矩阵可以使用 AI 辅助单元测试流程 起草,但预期结果必须来自当前业务规则。

第三步:选择最小可验证切口

优先选择重复逻辑、纯计算、边界清晰的适配层或难以替换的外部依赖包装。一次只抽取一个职责,例如参数校验、数据映射或通知发送,不要同时改变量命名、目录结构和业务规则。

让 AI 给出两个方案:保守方案保持接口不变;演进方案说明未来迁移路径。选择时看测试覆盖、依赖数量、回滚难度和团队理解成本,而不是代码看起来是否更短。

第四步:要求 AI 解释改动而非只输出补丁

每个建议都应回答:旧逻辑如何工作,新逻辑保持了哪些行为,可能改变什么,测试如何覆盖,失败时怎么回退。要求先输出计划和伪代码,再生成小块补丁,可以减少一次性重写的风险。

对于性能相关改动,先保存基准输入、数据规模和测量方式。没有可比较基线时,不要接受“更快”“更省内存”这类结论。

第五步:分层验证和审查

先执行新增或受影响的最小测试,再运行集成测试、静态检查和构建。变更进入评审时,按行为变化、异常处理、并发、权限、日志和可观测性检查。AI 可辅助列出风险点,但评审者应阅读真实 diff 和测试结果。

安全敏感模块还应独立执行 AI 代码安全审查工作流。重构不能因为“只是整理代码”而跳过权限、输入和密钥检查。

第六步:可回滚发布和后续清理

用特性开关、灰度、双写校验或只读影子流量降低上线风险,具体选择取决于业务副作用。记录发布前后关键指标和错误类型,异常时优先回滚到已知行为,而不是线上继续修改。

完成后再处理死代码、旧开关和临时兼容层。清理前确认没有调用方和历史任务依赖它们,并将决定写入变更记录。

重构护栏清单

  • 本次不改变的接口、数据和权限边界是否明确。
  • 当前调用链、异常路径和副作用是否已有证据。
  • 关键行为是否有可重复执行的测试。
  • 改动是否限制在一个可理解、可回滚的切口。
  • AI 建议是否解释了假设、风险和验证方式。
  • 性能结论是否有相同输入下的基准比较。
  • 发布是否有监控、开关或回滚方案。

常见问题

没有测试的遗留系统能重构吗

可以,但先补最关键的特征测试和监控。没有行为基线时,大规模重构相当于同时修改和猜测系统。

AI 一次生成的大补丁能直接合并吗

不建议。大补丁难以审查和回滚,应拆成职责单一的小变更,每步都有测试和明确的预期。

重构发现旧逻辑本身有 bug 怎么办

将修 bug 与保持兼容分开记录,补充复现测试,并让业务负责人确认是否需要修正历史行为。