Code Review 与复杂性预算:管住 AI 代码的出口

Vibe Coding; Code Review; 复杂性预算; 技术债; 代码质量 2930 words 15 min read
This post is not yet available in English. Showing the original.

前一篇讲的是入口——用结构化的 Prompt 决定 AI 往哪个方向生成。这一篇讲出口

已经把代码写出来了,你凭什么决定它能不能进你的代码库?

两头一卡,中间的质量才稳得住。入口靠 Prompt,出口靠 Code Review,而判断”进还是不进”的那把尺子,叫复杂性预算。

效率这个词需要重新理解

先破一个迷思。

AI 把写代码的速度拉高了。过去半天才能搭好的页面,现在十分钟搞定;过去对着文档查两小时的 API 对接,现在一句话丢过去就能拿到初稿。产出量涨了,这没什么好争的。

但有一个越来越强的感受:产出量涨了跟系统质量涨了,是两回事。 把这两件事混在一起,会出大问题。

做过项目的人对下面这个过程不会陌生。刚开始推进飞快,模块少,边界清楚,想怎么改就怎么改,很爽。但系统长到一定规模,情况就变了

,命名开始漂移,早期图省事留下的妥协固化成了结构惯性。团队投入没减少,人手可能还多了,但大家开始觉得”改不动了”。一个小改动要摸清楚它会影响哪些地方,光这件事就够累的,动手改反而是小头。

AI 没有改变这个过程,只是把它调快了。

在传统开发里,人手写代码本身就是一层天然的过滤器。你写得慢,草率的依赖、混杂的实现,扩散速度就是有限的。但 AI 协作环境不一样

,几轮生成之后就成了整个代码库默认的写法。后面的人看到前面这么写,不会多想;AI 也照着这个模式继续补。“不太好的做法”很快就变成了”项目的标准做法”,而且这个过程是静悄悄发生的。等你意识到的时候,已经改不动了。

AI 是一个忠实的放大器。你走对了路,它帮你加速;你走错了路,它也帮你加速,速度一样快甚至更快——因为走错路的时候你不会停下来仔细想。

所以现在看”效率”这个词要谨慎很多。“单位时间写了多少行代码”这个指标,在 AI 时代没有意义。工程上的效率得看更长的时间窗口

,结构还能不能承受变化,加新东西的时候有没有余地。如果你每次交付都在透支可维护性,那这种效率只是在借未来的债。

开发者当中流传一句杀伤力很大的话:“先这样吧,后面再改。” 但回头看,“后面再改”在大多数项目里没有一次自动发生过。每次都是等到问题大到不得不改,才发现改的成本比当初做对的成本高了好几倍。技术债拖得越久,利息越高。

复杂性预算

“复杂性预算”这个概念很少有人提,但做过大项目的人一定有体感。

一个项目在特定阶段内能承受的结构复杂度是有上限的。复杂性本身消除不了——任何系统都要处理状态、边界、异常、依赖和演化。你能管的,是复杂性进入系统的速度、位置和规模

AI 让这个问题变得格外尖锐。AI 可以源源不断地给出”看起来可用”的实现,团队只要缺少筛选机制,技术债就会以前所未有的速度累积。看似在往前跑,实际在往坑里滑。

所以要设一道关口

代码进入系统前,至少要过四道检查。

可读性。 维护者能不能在短时间内说清这段代码在干什么?一种很常见的情况

,测试也过了,但问作者”这段逻辑为什么要这么写”,他自己也说不清楚。这种代码进了主干就是定时炸弹。说不清的,先重写再合并。

职责边界。 每个函数和模块是不是只对应一个主要任务?那些跨层级堆叠、一个函数干五件事的实现,优先拆。

重复控制。 同一个规则是不是被复制粘贴到了三个地方?如果是,预算就在泄漏。AI 特别喜欢复制局部逻辑来快速满足需求——金额格式化在 A 文件写一遍,B 文件又写一遍,C 文件再来一遍,每个版本还不完全一样。

架构服从。 新代码进入系统时,在现有结构里有没有明确的位置?”写得顺手”不能成为偏离主线的理由。

还有几个信号一旦出现就要警惕:

  • 同一个需求的改动需要跨越太多文件,找不到主修改点
  • 新增功能必须先修补一堆历史遗留问题才能落地
  • 一次改动反复引入非预期回归

出现这些情况,说明局部复杂性已经超标了,再叠功能只会更糟。

预算不是均匀分配的。 核心业务模块和高频变更路径要保持更低的复杂度上限,外围适配层可以容纳一定的技术复杂度——前提是边界清楚而且可替换。不少项目把复杂度堆进了核心区,最后整个改不动,只能推倒重来。

Code Review 变成了第一基本功

过去 Code Review 是开发流程里的一个环节。现在,它正在变成编程活动的第一基本功

原因很直接

几分钟就能产出数百行代码,但团队要对这些代码承担长期责任。代码一旦合入主干,后续每一次迭代、排查、调整都会和它发生关系。AI 产出速度快,但你必须保留对每一行代码的解释权和否决权。

AI 时代的 Code Review 至少要覆盖四个维度:

正确性。 最常见的坑是”主路径能跑,但边界条件一塌糊涂”。AI 根据”贪吃蛇”这三个字凑出一个能跑的东西,但”连续按方向键会不会 180 度掉头撞死自己""窗口 resize 会不会重置状态”这些边界,它不会主动想。审查时重点盯边界。

可读性。 AI 有时候会用一些”技巧性写法”压缩长度,看起来简洁,实际上把理解成本甩给了未来的维护者。简洁 ≠ 可读。

可维护性。 盯住重复逻辑。前面说的”金额格式化写三遍”就是典型——AI 为了快速满足当前需求,倾向于复制而非抽象。

可演进性。 AI 有时候为了满足当前任务引入过重的依赖或过度的抽象,短期看很完整,长期代价极高。多问一句:“这个依赖/这层抽象,是这个任务真的需要,还是它顺手加的?”

一个比较稳妥的 PR 评审流程可以分五步:

  1. 需求对齐——这个 PR 到底要解决什么?和 Spec 对得上吗?
  2. 结构先行——先看它改了哪些文件、动了哪些边界,再看具体实现
  3. 证据驱动——不听”应该能跑”,看测试、看日志、看实际运行结果
  4. 问题分级——区分”必须改”(阻塞合并)和”可以后续优化”(记 issue),不要什么都卡
  5. 复审合并——改完再看一遍,确认没引入新问题

这个流程不复杂,但能有效降低那种”语法全对但架构歪了”的情况。

AI 编程时代里,你缺的不是能写代码的工具。你缺的是能看出问题的眼睛。

用测试给重构兜底

Code Review 是人工判断,但有一个能力可以让 AI 自己把代码质量往上抬,前提是你给它搭好安全网。

这个能力可以叫非退化性

,不会把正常代码误判为问题,同时能准确识别出真正有问题的代码。

听起来平平无奇,但它能推出一个很有用的结论。假设模型具备非退化性:

  1. 单次审查——带着某个具体问题(比如”有没有重复逻辑”)审查代码,AI 总能找到可以改进的地方
  2. 多次迭代——每次修改后,该类问题的出现次数递减
  3. 收敛——经过多轮审查,代码在这个维度上的问题趋近于零,对 AI 来说变得”平滑”,不再有突兀之处

进一步,如果每一个问题的解决都不会引入新问题,那么:预设足够多维度的重构清单,反复让 AI 带着相同的问题去重构,最终代码就会在所有这些维度上达标。

关键在于”每次修改不引入新问题”这个前提怎么保证——答案是测试集

操作方法:

  1. 构建安全网
  2. 预设问题清单
    AGENTS.md / CLAUDE.md 里列出重构维度(SOLID 原则、分层清晰、防御式编程、无重复逻辑……)
  3. 迭代优化
    AI 对照清单逐项优化

因为有测试兜底,任何破坏逻辑的修改都会让测试跑不通,AI 必须始终保持测试可以跑通。于是每一次重构都建立在”质量不会降低”的基础上,非退化性就能保证代码始终朝变好的方向迭代。

这也顺带回答了一个问题:是不是必须用最强的模型才能写出好代码? 不一定。理论上,一个中等模型只要”会做题”、稍微会写代码,靠反馈循环 + 非退化性,也能逐步逼近好代码。更强模型的价值在于更高效地做题——对复杂问题建模、根据长上下文和日志分析定位问题。分析能力有限的模型遇到硬 bug 会陷进去反复无效思考,而不是”写不出好代码”。

小结

  • 效率要看长窗口
    ≠ 系统质量,AI 是放大器,走错路它也帮你加速
  • 复杂性预算
    ,但你能管它进入系统的速度、位置、规模;核心区上限要低,外围可以宽
  • 四道关口
    、职责边界、重复控制、架构服从——过不了就别进主干
  • Code Review 是第一基本功
    (盯边界)、可读性、可维护性(盯重复)、可演进性(盯过度依赖)
  • 非退化性 + 测试兜底
    ,让 AI 自己把质量收敛上去

下一篇讲一个更上层的判断

AI 尽情 Vibe,什么时候必须切回工程纪律——探索区与生产区的边界。


本文主要参考:《Vibe Coding 到底是什么》(blog.byebug.cn)§06 复杂性预算、§08 Code Review;以及《一套简单有效的 Vibe Coding 实践》中的”非退化性”论证(linux.do)。