资讯动态

代码审查已死?用不变量思维和AI重构审查流程

发布时间:2026/10/14 18:31:43 来源:尧图企业网站定制
1. 代码审查怎么就成了走流程我做了十多年开发带过团队也做过那种跨部门的大型项目评审。说句不客气的话现在很多团队的代码审查已经彻底变味了。打开一个PR满屏都是“LGTM”、“1”、“看起来没问题”或者就是机器人自动跑一遍格式检查然后大家点个通过就合并了。你要是问某个变量为什么这么命名某个边界条件为什么没处理大概率没人说得上来。这就是我标题里说的“形式化代码审查”。它看起来在运转实际上已经死了。真正的问题在于我们把审查当成了一道流程关卡而不是一次技术对话。流程关卡只需要盖章技术对话才需要动脑子。当审查变成盖章代码质量的下滑就是必然的只是时间早晚的问题。我见过最离谱的一个案例一个涉及资金结算的核心模块PR里改动了金额计算的精度处理逻辑从float换成了double理由是“精度更高”。三个评审人全部点了通过。上线之后对账差了十几万。事后复盘没有一个人真正去看那段diff因为那个PR有四十多个文件变更大家都默认“别人看过了”。这件事让我彻底反思代码审查的本质到底是什么我的结论是代码审查的本质是知识传递和风险发现而不是流程合规。知识传递意味着评审者要理解作者的意图作者要理解评审者的顾虑风险发现意味着要主动去找那些测试覆盖不到、静态检查扫不出来的逻辑漏洞。这两件事没有一件能靠“点通过”完成。所以这篇文章我想认真聊聊怎么把代码审查从形式主义的泥潭里拉出来。我会讲清楚为什么现在的审查会失效怎么用不变量思维去审查代码AI和智能体在这个过程里到底能帮什么忙、不能帮什么忙以及一套我自己在团队里跑了大半年、确实有效的审查方法。不管你是刚入行的新人还是带了多年团队的Tech Lead应该都能从里面找到能直接用的东西。2. 形式化审查的根子出在哪2.1 把审查当门禁而不是当对话大部分团队对代码审查的定位从一开始就错了。他们把审查当成一道门禁代码要合入主干必须经过审查。这个定位本身没错但问题在于门禁的默认状态是“关闭”要通过就得“开门”。于是评审者的心理模式变成了“找理由不放行”而不是“找问题帮改进”。作者的心理模式变成了“想办法让评审者放行”而不是“想办法让代码更好”。这两种心理模式一旦形成审查就变成了博弈。作者会把PR拆得很碎让每个PR看起来都很小、很安全评审者会快速扫一眼只要没有明显语法错误就放行。双方都在追求“快速通过”而不是“质量提升”。我见过有团队甚至把“PR平均评审时长”当成KPI来考核结果就是评审时长确实短了但线上事故率上去了。正确的定位应该是审查是一次结构化的技术对话。作者通过PR向团队解释自己的设计决策评审者通过评论提出质疑和建议双方通过讨论达成共识。这个过程的目标不是“通过”而是“理解”和“改进”。通过只是自然结果不是目标本身。2.2 评审者根本没有足够的上下文我做过一个统计在我们团队过去的PR里评审者平均花在每个PR上的时间是4分32秒。而PR的平均变更行数是287行。这意味着评审者每分钟要看60多行代码。这个速度别说理解逻辑了连看清楚变量名都费劲。为什么会这样因为评审者没有足够的上下文。他们不知道这个改动的背景是什么不知道作者尝试过哪些方案不知道哪些地方是刻意为之、哪些地方是疏忽。他们看到的只是一堆diff然后凭直觉判断“看起来有没有问题”。这个问题在大型项目里尤其严重。一个模块可能经过五六个人的手每个人只了解自己写的那部分。当有人改动了一个跨模块的接口评审者往往只能看到自己熟悉的那部分对其他部分的影响完全靠猜。这种审查与其说是审查不如说是盲人摸象。2.3 工具把审查简化成了“通过/拒绝”现在的代码托管平台把审查简化成了两个按钮Approve和Request Changes。这个设计本身没问题但它诱导了一种二元思维要么通过要么拒绝。可实际上代码审查的结论远不止这两种。有时候代码有问题但可以合并后再修有时候代码没问题但设计思路值得讨论有时候需要作者补充说明才能判断。更糟糕的是很多团队把“Approve数量”当成评审者的贡献指标。于是评审者倾向于快速Approve因为这样显得自己“高效”。我见过有评审者在一天之内Approve了二十多个PR平均每个PR的评审时间不到两分钟。这种“高效”实际上是对团队的不负责任。2.4 作者和评审者的信息不对称还有一个根本问题作者和评审者之间的信息不对称。作者花了三天写这个功能脑子里有完整的上下文评审者只有十分钟看到的只是最终结果。作者觉得“这个改动很明显啊”评审者觉得“这到底在改什么”。这种不对称导致两个后果。第一作者会不自觉地省略关键信息觉得“评审者应该能看懂”第二评审者会不自觉地跳过不熟悉的部分只评审自己看得懂的地方。结果就是真正有风险的地方反而没人看。我后来在团队里推行了一个规矩每个PR必须包含一段“背景说明”讲清楚这个改动要解决什么问题、尝试过哪些方案、为什么选这个方案、有哪些已知的取舍。这段说明不写清楚评审者有权直接打回。这个规矩推行之后PR的平均评审时间反而缩短了因为评审者有了上下文不用再靠猜。3. 回归本质审查到底在审什么3.1 审查的第一目标是发现逻辑漏洞测试能发现的问题不需要审查来发现。静态检查能发现的问题也不需要审查来发现。审查要发现的是那些测试覆盖不到、静态检查扫不出来的逻辑漏洞。什么是逻辑漏洞举个例子一个订单状态机测试覆盖了所有正常流转路径但没覆盖“已取消订单再次取消”这种异常路径。静态检查也扫不出来因为代码语法完全正确。只有人去看代码才能发现“取消”操作没有校验当前状态。再举个例子一个并发场景两个线程同时修改同一个计数器。测试在单线程环境下跑得好好的静态检查也看不出问题。只有人去看代码才能发现缺少锁保护。这类问题才是审查真正要抓的。而形式化审查恰恰抓不到这类问题因为评审者根本没有深入去看逻辑。3.2 审查的第二目标是传递知识代码审查是一个团队学习的过程。作者通过写代码表达自己的设计思路评审者通过阅读代码学习新的模式和方法。这个过程是双向的新人可以从评审者的评论里学到最佳实践老人可以从新人的代码里看到新的思路。我特别看重这一点。我们团队有个规矩每个PR至少要有一个人留下一条“实质性评论”不能只是“LGTM”。这条评论可以是提问、可以是建议、可以是质疑但必须是实质性的。这个规矩逼着评审者真正去看代码而不是走过场。3.3 审查的第三目标是统一团队认知同一个问题不同的人可能有不同的解法。代码审查是一个统一认知的机会。通过讨论团队可以达成共识以后遇到类似问题就用这个方案。这种共识比任何文档都有效因为它是通过实际代码讨论出来的。我见过很多团队代码风格五花八门每个人都有自己的写法。问起来都说“能跑就行”。这种团队代码维护成本极高因为每个人都要花大量时间去理解别人的代码。代码审查就是解决这个问题的抓手。3.4 审查的第四目标是建立质量文化这一点最虚但也最重要。当一个团队认真对待代码审查认真讨论每一个设计决策认真寻找每一个逻辑漏洞这个团队的质量文化就建立起来了。反过来如果审查只是走过场那质量文化就是一句空话。我自己的体会是质量文化不是靠制度建立的而是靠一次次具体的审查行为积累起来的。当评审者认真提出一个逻辑漏洞作者认真修改并感谢这个行为本身就在强化质量文化。当评审者敷衍了事作者也敷衍了事质量文化就在一点点瓦解。4. 用不变量思维重构审查方法4.1 什么是不变量不变量这个概念在算法领域用得很多。比如选择排序的循环不变量是在每轮迭代开始时数组的前i个元素已经有序。这个性质在每轮迭代开始时都成立在迭代过程中保持不变。把这个概念引入代码审查就是在代码执行的任何时刻都必须成立的性质。比如一个银行账户不变量是“余额永远不能为负”。不管发生什么操作这个性质都必须成立。用不变量思维审查代码就是去找那些“必须成立但代码没有保证”的性质。这比逐行看代码高效得多也深入得多。4.2 怎么从代码里提取不变量提取不变量有几个常用的切入点。第一个切入点是状态机。任何有状态的对象都有状态转移的不变量。比如订单状态机不变量是“已完成的订单不能再次支付”。审查代码时就要去看每个状态转移是否都校验了前置状态。第二个切入点是并发。任何共享可变状态都有并发不变量。比如计数器不变量是“任何时刻的值都等于所有增量之和”。审查代码时就要去看所有修改共享状态的地方是否都有正确的同步。第三个切入点是资源。任何资源内存、文件句柄、数据库连接都有生命周期不变量。比如文件句柄不变量是“打开后必须关闭”。审查代码时就要去看所有打开资源的地方是否都有对应的关闭逻辑包括异常路径。第四个切入点是边界。任何涉及数值计算的地方都有边界不变量。比如数组索引不变量是“索引必须在合法范围内”。审查代码时就要去看所有访问数组的地方是否都做了边界检查。4.3 用不变量审查的实际案例我拿一个真实的案例来说明。有一次我们团队的一个PR改动了一个缓存模块。改动内容看起来很简单把缓存的过期时间从固定值改成了可配置值。评审者一开始都点了通过因为改动确实很小。但我用不变量思维看了一遍发现了一个问题。原来的代码里缓存过期时间是一个常量所以“缓存项一旦写入过期时间就不会变”这个不变量是天然成立的。改成可配置值之后这个不变量就不成立了如果配置在运行时被修改已经写入的缓存项的过期时间会怎么处理代码里没有处理这个情况。结果是配置修改后新写入的缓存项用新过期时间老缓存项用老过期时间导致缓存行为不一致。这个问题测试没覆盖静态检查也扫不出来只有用不变量思维才能发现。4.4 把不变量写进PR描述我后来在团队里推行了一个做法每个PR的描述里必须列出这个改动涉及的不变量。比如“本改动涉及缓存过期时间不变量已确保配置修改后所有缓存项行为一致”。这个做法有两个好处一是逼着作者自己想清楚不变量二是让评审者有了明确的审查目标。这个做法推行之后我们团队的线上事故率下降了差不多四成。不是说所有事故都能靠这个避免但至少那些“逻辑漏洞”类的事故明显少了。5. AI和智能体在审查里的正确用法5.1 AI能做什么不能做什么现在大家都在聊AI辅助代码审查好像AI一上审查问题就解决了。我的看法是AI能帮大忙但别指望它解决所有问题。AI擅长的是模式识别。比如识别常见的代码坏味道、识别潜在的空指针、识别不一致的命名风格。这些事AI做得比人快也比人稳。我们团队现在用AI做第一轮扫描把那些明显的问题先过滤掉评审者就不用花时间在这些低级问题上了。但AI不擅长的是理解意图。它不知道这段代码要解决什么业务问题不知道作者为什么选这个方案不知道哪些地方是刻意为之。所以AI发现的问题需要人来判断是不是真问题AI没发现的问题不代表没有问题。5.2 智能体在审查流程里的定位智能体Agent比单纯的AI模型更进一步。它可以主动执行一系列操作比如拉取代码、运行测试、分析依赖、生成报告。在审查流程里智能体可以承担很多重复性工作。我们团队现在用智能体做几件事。第一自动检查PR描述是否完整如果不完整就自动打回并提示作者补充。第二自动运行相关测试如果测试失败就自动评论并附上失败日志。第三自动分析改动的依赖影响如果改动涉及跨模块接口就自动通知相关模块的负责人。这些事看起来简单但确实省了评审者很多时间。评审者可以把精力集中在真正需要人判断的地方而不是浪费在流程性事务上。5.3 多AI协作审查的实践我们最近在尝试多AI协作审查。具体做法是用不同的AI模型分别审查同一个PR每个模型关注不同的维度。比如一个模型专门看逻辑漏洞一个模型专门看性能问题一个模型专门看安全问题。然后把所有模型的发现汇总起来由人来判断哪些是真问题。这个做法效果不错。不同模型的视角不一样能发现一些单一模型发现不了的问题。但缺点是成本高而且汇总结果需要人来过滤不然会有大量误报。我的建议是如果团队规模不大先用单一AI做基础扫描就够了。等多AI协作的成本降下来再考虑上多AI。5.4 AI审查的边界和风险AI审查有几个边界要注意。第一AI不能替代人的判断。AI发现的问题必须由人来确认是不是真问题。第二AI不能理解业务上下文。它不知道这个业务场景下什么是对的、什么是错的。第三AI可能产生误报。如果评审者盲目相信AI可能会把好代码当成坏代码。还有一个风险是AI审查可能让评审者更懒。如果评审者觉得“AI都看过了应该没问题”就会跳过自己的审查。这个风险很现实我见过不少团队踩这个坑。所以我的建议是AI审查的结果只能作为参考不能作为结论。评审者该看的代码还是得看。6. 一套可落地的审查流程6.1 PR提交前的自检清单作者在提交PR之前应该先做一轮自检。这个自检清单我们团队用了大半年效果不错。改动是否只做了一件事如果一个PR做了多件事拆成多个PR。PR描述是否包含了背景、方案、取舍、不变量缺一项就打回。是否运行了相关测试测试是否全部通过是否检查了改动的依赖影响是否通知了相关模块负责人是否检查了边界条件和异常路径是否检查了并发场景是否检查了资源释放这个清单看起来长但实际操作起来熟练之后五分钟就能过一遍。关键是养成习惯。6.2 评审者的审查步骤评审者拿到PR之后按以下步骤审查。第一步读PR描述。如果描述不完整直接打回不用看代码。这一步能过滤掉大量低质量PR。第二步看改动范围。如果改动涉及多个模块先看接口改动再看实现改动。接口改动的影响面大需要优先审查。第三步用不变量思维审查核心逻辑。找出改动涉及的不变量逐个检查代码是否保证这些不变量。第四步检查边界和异常。看所有涉及数值计算、数组访问、资源操作的地方是否都处理了边界和异常。第五步检查并发。看所有共享可变状态是否都有正确的同步。第六步留下实质性评论。至少一条可以是提问、建议或质疑。这个步骤看起来多但熟练之后一个中等规模的PR二十分钟能审完。比那种四分钟扫一遍、然后线上出事故再回头查效率高多了。6.3 审查会议的召开方式有些团队会开审查会议大家一起过PR。这个做法有利有弊。利是能集思广益弊是效率低而且容易变成“作者讲、大家听”的单向输出。我的建议是只在两种情况下开审查会议。第一种是改动涉及核心模块影响面大需要多人确认。第二种是改动涉及有争议的设计决策需要团队讨论达成共识。其他情况用异步审查就够了。开审查会议时作者先讲背景和方案然后评审者提问和讨论最后达成共识。会议时间控制在半小时以内超过半小时就说明PR太大应该拆分。6.4 审查结果的跟踪和闭环审查不是终点合入才是。审查发现的问题必须跟踪到解决为止。我们团队用了一个简单的做法每个审查评论都必须有一个明确的结论要么“已修改”要么“已讨论不改”要么“转成后续任务”。没有结论的评论不允许合入。这个做法逼着作者和评审者把每个问题都闭环。我见过太多团队审查评论提了一堆最后不了了之。这种审查提了等于没提。7. 常见问题与避坑指南7.1 作者觉得评审者太苛刻怎么办这个问题很常见。作者花了几天写的代码评审者提了一堆问题作者觉得被针对了。我的建议是把审查当成学习机会而不是评判。评审者提的问题不管对不对都先想一想为什么他会这么提。如果确实是自己疏忽就改如果是评审者误解就解释。解释的过程也是统一认知的过程。7.2 评审者觉得作者不配合怎么办反过来评审者提了问题作者不改评审者觉得作者不配合。我的建议是先确认问题是不是真问题。如果是真问题坚持要求修改如果是风格问题可以讨论后决定。关键是评审者要给出明确的理由而不是“我觉得这样不好”。有理由的评论作者更容易接受。7.3 PR太大怎么审PR太大是审查失效的主要原因之一。我的建议是强制拆分。一个PR的变更行数控制在400行以内。超过400行必须拆分。拆分的原则是每个PR只做一件事。如果一件事确实需要改很多文件那就分多个PR每个PR改一部分。7.4 审查时间不够怎么办审查时间不够本质上是优先级问题。如果团队真的重视质量就应该给审查留出足够的时间。我的建议是把审查时间算进开发时间。比如一个功能预计开发三天那就预留半天做审查。这样就不会出现“没时间审查”的情况。7.5 怎么让新人快速上手审查新人审查代码最大的问题是不知道看什么。我的建议是给新人一个审查清单让他按清单逐项检查。清单可以从简单的开始比如“变量命名是否清晰”、“是否有明显的逻辑错误”然后逐步增加难度比如“是否处理了边界条件”、“是否有并发问题”。清单用熟了新人自然就知道看什么了。7.6 审查和测试的关系怎么处理审查和测试不是替代关系而是互补关系。测试覆盖正常路径审查覆盖异常路径。测试覆盖已知场景审查发现未知风险。我的建议是测试必须通过才能进入审查但测试通过不代表审查可以放松。审查要关注那些测试覆盖不到的地方。8. 我自己的几点体会最后说几点我自己的体会不一定对但都是踩过坑之后总结出来的。第一审查的质量取决于评审者的投入程度。如果评审者只是走过场再好的流程也没用。所以选评审者比定流程更重要。我现在的做法是每个PR指定一个“主评审人”这个人必须认真审其他人可以辅助。主评审人对审查质量负责。第二审查的文化比审查的工具更重要。工具再好如果团队不重视质量审查还是走过场。所以建立质量文化是审查改革的第一步。怎么建立从认真对待每一个审查评论开始。第三审查的收益是长期的。短期内认真审查会拖慢开发速度。但长期看认真审查能减少线上事故、降低维护成本、提升团队能力。这个账要算长期账不能算短期账。第四AI和智能体是帮手不是替代。它们能帮我们过滤低级问题、节省时间但不能替代人的判断。审查的核心还是人对代码的理解和判断。这一点短期内不会变。第五审查的最终目标是让代码更好而不是让流程更顺。如果流程和代码质量冲突选代码质量。流程是为人服务的不是人为流程服务。我现在的团队PR平均评审时间是二十五分钟比之前的四分钟长了六倍。但线上事故率下降了六成代码维护成本下降了四成。这个投入产出比我觉得很值。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑