首页 / 资讯中心 / 文章详情

ChatGPT、Codex工程方法:旧项目准备大重构,为什么第一步反而是先锁定“行为基线”?

ChatGPT、Codex工程方法:旧项目准备大重构,为什么第一步反而是先锁定“行为基线”? ★ FEATURED ARTICLE
最近用 ChatGPT、Codex 接手旧项目时我越来越不建议第一句话就是“帮我把这个模块重构一下。”尤其是那种已经跑了三五年、代码风格很乱、测试又不完整的项目。表面看起来最值得做的是拆大类。改命名。抽公共逻辑。调整目录。重写接口。把历史遗留代码全部整理一遍。Codex做这些事情确实很快。但真正危险的地方也在这里代码可以很快变漂亮系统原来那些没人写进文档里的行为也可能一起被改掉。比如一个旧订单接口。你看代码的时候觉得特别不合理订单不存在时居然返回200。某个字段明明没有值却返回空字符串而不是null。重复提交时不报错而是直接返回第一次结果。某个状态明明已经废弃很多年旧客户端却还在使用。从“代码设计”角度看这些都很想顺手改掉。但问题是它们可能早就变成了真实系统的一部分。所以旧项目大重构之前我现在更关注的第一件事不是“怎么改得更漂亮”而是“这个系统现在实际上是怎么工作的”这就是Behavior Baseline——行为基线。一、旧代码最危险的地方不是乱而是“没人知道哪些乱不能动”一个成熟旧项目里通常同时存在三种东西。第一种真正的技术债。比如重复代码、糟糕命名、不合理的依赖。第二种历史兼容行为。看起来不好看但外部系统已经依赖。第三种没人解释得清的特殊逻辑。比如if amount 0: return success你可能觉得这段完全多余。但继续查才发现三年前有一批历史订单就是靠这条逻辑兼容。如果Agent一上来就按照“最佳实践”重写最容易把第二类和第三类一起当成第一类处理。这也是为什么Cleaner Code ≠ Safer Refactor代码更干净不代表重构更安全。二、为什么Agent特别容易在旧项目里“改对代码却改错行为”因为 ChatGPT、Codex 最容易看到的是当前代码结构。类型定义。调用关系。测试。但旧项目真正的行为契约往往散落在线上数据。客户端调用方式。历史接口响应。数据库副作用。消息事件。配置。甚至运营人员的使用习惯里。如果这些没有明确给出来Agent很自然会认为当前代码就是全部真相。于是它可能主动修掉一些“看起来不合理”的地方。比如把200 error message改成标准的404从HTTP设计角度看可能更合理。但如果旧客户端只判断200线上立刻出问题。所以旧项目重构真正难的不是Agent不会写新代码。而是旧系统的真实契约往往没有被显式记录。三、所以第一步不是Refactor而是Characterize重构前我更推荐先做Characterization——行为刻画。简单说就是先把系统现在的关键行为记录下来。不是先判断“这样设计对不对”。而是先确认“现在它确实就是这么工作”。例如一个旧接口可以先记录正常输入返回什么空数据返回什么非法参数返回什么会写哪些数据库表会不会发消息重试会不会产生重复副作用历史数据怎么处理P95大概多少哪些旧客户端仍然依赖。这些东西加起来才是真正的行为基线。四、Characterization Test和普通单测不完全一样普通单测经常表达的是“代码应该怎么工作。”而Characterization Test更接近“代码现在实际上怎么工作。”这两者区别很重要。例如当前系统订单不存在时返回HTTP 200 code ORDER_NOT_FOUND你可能觉得这不合理。但重构前可以先把这个行为锁下来。不是说以后永远不能改。而是如果要改必须明确知道自己正在改变兼容行为。这样重构就从“无意识破坏”变成“有意识变更”。五、行为基线不只包括API输出这是最容易缩窄的地方。很多人想到Behavior Baseline只想到接口返回值。其实真实项目里至少还应该看几类。API行为状态码。字段结构。错误语义。数据行为写哪些表。字段默认值。事务边界。历史数据兼容。副作用是否发消息。是否调用第三方。是否写缓存。时序行为同步还是异步。先写库还是先发事件。性能行为某些核心链路能不能接受重构后的额外耗时。因为有时候代码功能完全正确但从300ms变成3秒一样不能算成功重构。六、先锁“必须保持”再决定“允许改变”旧项目重构最实用的一个动作是把行为分成两类。第一类Must Keep必须保持。比如旧API兼容。历史数据可读。同一请求不能重复扣款。第二类Allowed to Change允许改变。比如内部类结构。方法命名。模块拆分。缓存实现。这样Agent就不会把所有“现状”都当成必须永久保留。也不会把所有“不好看”都当成可以随便改。真正的重构自由应该是实现可以大改关键行为不能偷偷变。七、一个比较稳的重构流程我现在更推荐让 ChatGPT、Codex 按这个顺序做Capture Current Behavior先收集现有行为。↓Define Must-Keep Behavior确认哪些行为必须保留。↓Refactor再开始改实现。↓Compare新旧结果对比。↓Accept确认行为没有意外变化再接受当前Change Set。这个顺序和直接“读代码 → 重构 → 跑测试”最大的区别是重构前已经有了比较对象。否则测试一旦不完整你甚至不知道Agent到底改变了什么。八、为什么旧项目测试越少越应该先做行为基线很多人会觉得项目测试都没有怎么做基线恰恰相反。测试越少越不能直接大改。因为这个时候唯一能保护你的不是原来的Test Suite而是先补一批关键行为快照。不需要一开始就把覆盖率补到80%。只要先锁几个真正关键场景核心API。核心数据写入。关键异常。关键副作用。历史兼容。就已经比裸重构安全很多。九、可以让Agent先做“只读阶段”复杂旧项目我比较喜欢先给Codex一个明确限制先不要修改代码。先完成找核心入口列关键调用链识别外部依赖找关键副作用收集现有测试输出建议锁定的行为基线。这样第一阶段的目标不是产出Diff。而是产出对当前系统的理解。确认以后再进入Write阶段。这会明显减少刚读几个文件就开始大范围重构。十、行为基线还能帮助ReviewAgent一次改几十个文件以后单纯看Git Diff特别累。但如果前面已经定义“这5个行为必须保持”Review就简单很多。你不再需要逐行确认所有代码。而是优先验证这些关键行为有没有变化。比如老客户端还能不能调用历史数据还能不能读重复请求是否仍然幂等Event Schema有没有变化P95有没有明显恶化。这相当于把Review从代码中心变成行为中心。十一、什么时候应该允许行为变化行为基线不是让旧项目永远不能改变。如果某个旧行为本身就是Bug当然可以改。但变化最好显式化。比如OLD: 订单不存在 → HTTP 200 NEW: 订单不存在 → HTTP 404然后明确哪些客户端需要升级。何时切换。如何灰度。如何回滚。这和Agent直接“顺手修正”是完全不同的。前者是Planned Behavior Change后者是Accidental Behavior Change真正要防的是后者。十二、给自己看一个指标行为保持率这篇只看一个指标Behavior Preservation Rate——行为保持率可以简单理解为重构前确认必须保持的关键行为中重构后仍然保持一致的数量 ÷ 必须保持的关键行为总数例如重构前锁定10个关键行为。完成以后9个保持一致。1个在Review时发现已经变化。那么行为保持率 90%。对于关键兼容行为来说这个数字最好尽量接近100%。因为这些本来就是你提前定义的不能被无意改变的部分。十三、行为保持率低先别急着继续重构如果每改一轮老接口坏一个。历史数据出一个问题。消息格式又变化。说明真正的问题不是Codex修改能力不够。而是行为边界没有建立好。这时候继续让Agent多改几个模块通常只会增加Review成本。更值得先回去补Behavior Baseline。Characterization Test。Must-Keep List。再继续下一阶段。十四、Plus和Pro怎么判断如果你的场景主要是偶尔接手一个旧项目。做局部重构。一次只改少量模块。主要让 ChatGPT、Codex 帮你读代码、补Characterization Test、分析影响范围这种使用强度下Plus通常已经够用。真正值得先做的是把关键行为锁清楚而不是直接追求更大的AI容量。如果你的实际工作已经变成长期维护大型旧项目。一次重构涉及几十个文件、多个模块。需要Agent持续分析、修改、跑测试、做行为对比、回归验证。同时还有多个复杂Change Set排队这时候Pro会更适合。因为更多任务容量可以真正用于长时间重构。多轮验证。大范围代码理解。但前提仍然是Behavior Baseline先建立起来。否则Agent改得越快你只是更快地失去“到底什么不能变”的判断能力。最后旧项目准备大重构为什么第一步反而不是改代码因为旧系统最危险的地方往往不是代码有多乱。而是你已经不知道哪些行为其实不能动。所以真正稳的重构起点应该是先观察。先记录。先锁定关键行为。再开始改。让 ChatGPT、Codex 先回答“这个系统现在实际上怎么工作”再回答“我们准备把它改成什么样”当Behavior Baseline存在以后重构才真正从把代码写得更漂亮变成在不破坏关键行为的前提下把系统改得更好。这才是旧项目大规模Agent重构真正值得守住的第一条边界。持续分享 Codex、大模型开发与 AI 编程实战内容。长期深度使用各类代码大模型也整理了稳定的Plus/Pro会员订阅渠道有需要可自取。
阅读完成 · 觉得有帮助?
咨询建站