重构旧代码(Legacy Code Refactoring)是 AI 编程中最容易翻车的场景,但也是回报率最高的场景。
旧代码就像一座"深水炸弹"堆积的古墓:缺乏文档、没有单测、充斥着全局变量、面条代码,甚至还隐藏着许多当年为了适配特定硬件或业务漏洞而写的"防御性补丁"(Bug-compatible coding)。如果直接对 AI 说"帮我重构这段代码",AI 大概率会用最新的语法写一段看起来极度优雅、但一上线就导致系统崩溃的全新 Bug。
要让 AI 安全、高质地重构旧代码,必须采用"解耦-锁死-重构-验证"的四步闭环工程(Loop Engineering)。
1. 核心四步重构工作流
绝不要让 AI 裸奔重构。请遵循以下严格的工程步骤:
[第一步:理解与解耦] ──► 抽取核心状态机/业务矩阵,让 AI 解释每一行古怪逻辑
│
▼
[第二步:单测锁死] ──► 【核心】重构前,让 AI 针对旧代码生成黑盒/白盒测试桩
│
▼
[第三步:分步重构] ──► 严格限定重构范围,每次只重构一层(如先抽接口,再改实现)
│
▼
[第四步:双环对齐验证] ──► 用第二步的单测同时跑新旧代码,确保"输入-输出"绝对等价
第一步:让 AI 当"考古学家",挖掘隐藏逻辑
在动手前,先让 AI 帮你梳理旧代码的逻辑。尤其是那些长达数百行的面条代码。
-
Prompt 话术:
"请分析这段旧的 C# 函数。请帮我梳理出它内部隐藏的核心业务状态机 、所有的条件分支 以及非托管资源销毁点 。请特别帮我找出:有没有哪些看起来不合理、但可能为了防止硬件抖动或特定边界而写的异常捕获(如
catch(Exception))?先不要重构,只做逻辑和依赖梳理。"
第二步:利用 AI 建立"防护网"(单测锁死)
这是重构成功唯一的底牌。 在修改任何一行代码之前,必须让 AI 针对旧代码生成密集的单元测试(或测试集)。
-
Prompt 话术:
"基于你刚才对这段旧代码的分析,请使用 xUnit 编写一套完整的功能对齐测试集 。需要包含常规等价类、极端边界值(如
null、空字符串、最大/最小值)。这组测试的目标是:通过给定的输入,验证旧代码的输出。 请确保测试覆盖到每一个老分支,我要用它来锁死新代码的行为。"
第三步:限定框架,让 AI 实施"渐进式重构"
重构时,必须给 AI 戴上"紧箍咒",限制它的架构边界。比如你是要把旧的 WinForms 逻辑重构到 WPF 的 ViewModel 中,或者是想引入设计模式。
-
Prompt 话术:
"现在,请将上述旧代码重构为符合 MVVM 架构 的高内聚代码。 硬性约束:
-
必须将核心业务逻辑抽离到一个独立的 Service 类中,并通过接口(Interface)进行解耦。
-
严禁改变原有的数学公式计算顺序和硬件寄存器读写时序。
-
所有的异步调用必须严格使用
await并加上ConfigureAwait(false),防止 UI 线程死锁。 -
使用更加现代的 C# 12 语法(如 Pattern Matching、Primary Constructors)提升可读性。"
-
第四步:双环对齐验证(Diff Testing)
重构完成后,将新代码替换进第二步的测试桩中。只有新旧代码在同一套测试集下 100% 跑通,重构才算初步成功。
2. 针对旧代码重构的"防翻车"三大铁律
铁律一:警惕 AI 删掉"有用的废代码"
在工业控制或老旧业务系统中,经常会有一些看似多余的代码。
-
经典反例: 连续两次读取同一个硬件寄存器,或者在方法开头有一个看似无用的
Thread.Sleep(5)。 -
AI 的反应: AI 的洁癖倾向会认为这是低级代码,并自作聪明地将其优化掉。
-
对策: 在重构 Prompt 中必须强调:
"如果遇到无法通过上下文推导出的冗余逻辑、或带有特殊硬件通信的步骤,请保留并加上 // TODO 注释询问我,绝对不允许擅自删除。"
铁律二:控制重构的"颗粒度"
不要试图让 AI 一次性重构一个拥有几十个类的老旧模块。大模型的上下文窗口虽然大,但随着生成的代码变长,它对架构一致性的掌控力会线性下降。
-
正确做法:
-
第一步:只让 AI 做局部重构(如把一个 500 行的方法重构为 5 个 100 行的内聚方法)。
-
第二步:做接口重构(如将紧耦合的类抽取成依赖注入模式)。
-
第三步:做异步化改造 (如将旧的同步阻塞通信重构为
Task异步流)。
-
铁律三:利用"主副双 Agent"进行架构交叉审查
如果你使用的是支持多 Agent 的工具(如 Cursor、Claude Code 或自建团队工作流),可以让两个 AI 扮演不同的角色进行对抗:
-
Agent A(重构专家): 专门负责用最新的模式、最优雅的语法改写代码。
-
Agent B(严苛的审计员): 拿着老代码、架构规范守则和单测报告,专门挑 Agent A 的刺,寻找"新引入的死锁风险、未释放的资源指针、越权调用的命名空间"。
通过这种主副 Agent 相互博弈、单测硬卡行为边界的方式,旧代码的重构将不再是一场靠运气决定系统是否崩溃的豪赌,而会变成一项可控、高效的流水线式工程。
