
1. 为什么我把 code review 从可做可不做变成必做先说个真实的翻车现场。前两年我们团队有个服务一直跑得好好的直到某次大促前一天晚上流量一上来接口直接雪崩。查了半天根因是一个同事提交的代码里把缓存超时时间从 60 秒改成 600 秒。他本意是减少缓存穿透结果下游数据变更后的可见性差了 10 倍用户看到的一直是旧数据。这个改动当时有没有人 review有而且 review 的人还点了 approve。为什么因为大家当时默认能跑就行review 就是走个流程。从那以后我开始认真琢磨一件事code review 到底怎么搞才能真正拦住问题而不是变成一种仪式感很强的形式主义。后来我花了大概两个月的时间把团队的 code review 流程重新梳理了一遍形成了一套相对固定的做法我管它叫 open-code-review。名字里带 open不是说要开源而是指整个审查过程对所有人开放规则开放、过程开放、结果开放。这套东西落地之后线上故障确实少了更重要的是团队里新人的成长速度变快了。这篇文章就把我这套做法的完整思路、实操细节、踩过的坑都写出来。适合正在为 code review 形式化发愁的技术团队负责人、技术组长也想给个人项目加上代码审查环节的独立开发者。内容不挑语言和框架核心思路通用。1.1 代码审查不是在找茬是在建立安全网很多人对 code review 的第一反应是被审 被质疑所以抵触情绪天然存在。但如果把代码审查当成一道安全网来看心态就会不一样。我做 open-code-review 第一个原则就是把人和代码分开。审查的对象永远是代码不是写代码的人。哪怕是团队里最资深的工程师写出有问题的代码也是正常的事因为人在连续写几个小时代码之后注意力一定会下降。这时候第二双眼睛看到的往往就是自己忽略掉的东西。还有一个经常被忽略的价值知识传递。新人通过 review 资深同事的代码能快速了解团队的技术规范和业务逻辑。资深同事通过 review 新人的代码能发现哪些地方文档没写清楚、哪些地方口头约定新人根本不知道。这种双向的信息流动比任何培训都有效。1.2 传统 code review 为什么容易流于形式我见过太多团队的 code review 是这样的PR 挂了两天没人理临上线前有人点了个 approve或者干脆LGTM完事。问就是大家都忙问就是改动很简单不用看。但仔细想一想本质上不是大家不愿意 review而是没有一个机制逼着大家认真 review。传统模式的问题出在三方面。一是没有规则每个人审什么都凭感觉有人只看格式有人只看逻辑结果看下来覆盖率很低。二是没有节奏PR 挂着没人跟进等真正需要合入的时候已经积压了一堆改动根本没法认真看。三是没有反馈闭环review 出来的意见改没改、改对了没有没有追踪时间一长大家就觉得提了也白提。op-code-review 的核心就是把这三件事都用明确的规则和工具固定下来。规则相当于把什么算好代码这个模糊概念变成一个可以对照检查的清单节奏保证 review 不会成为瓶颈闭环保证每一条意见都有下落。1.3 开放式到底开放了什么open-code-review 的 open我理解成三层意思。第一层是规则开放。审查标准不是某个技术大佬脑袋一拍定的而是团队一起讨论出来的并且文档化、可查询。谁有异议随时提出来改规则而不是私下吐槽。第二层是过程开放。所有 PR 的审查历史、评论、修改记录都是公开的任何成员都能看到某个改动为什么被拒绝、为什么被通过。这对新人尤其友好等于把团队的决策过程直接摊开给他们看。第三层是数据开放。我会定期统计团队的 review 数据包括平均响应时间、每轮修改次数、最常见的缺陷类型然后公开给全员。这些数据不是为了考核谁而是让大家看到流程哪里堵了、哪里需要优化。2. 核心设计思路与规则拆解2.1 审查规则文件怎么设计才不纸上谈兵我见过很多团队的 code review 规范文档写了几十页从变量命名到函数长度到注释规范几乎是百科全书。但实际执行下来没人会真的打开文档逐条对照。所以我在设计 open-code-review 的时候把规则收敛成一张 A4 纸能写完的清单。规则分三个优先级P0 是阻断级别发现必须打回比如明显的空指针风险、资源泄漏、敏感信息硬编码、明显的并发问题。P1 是建议修改比如逻辑边界没处理、异常日志缺失、性能隐患。P2 是偏好建议比如命名风格统一、代码格式调整这一类不强制提出来供作者参考。拿一个具体的例子说明。我们团队有一条 P0 规则是所有外部输入必须校验。早期有个接口没做参数长度校验结果被一个恶意请求把内存打满了。从那以后这条就进了 P0 清单。这类规则的来源不是凭空想象而是每一次线上事故的复盘结论。我会在复盘时专门问一个问题如果 review 时注意了哪一点这个事故可以避免答案沉淀下来就成了规则。规则文件我用 Markdown 维护在仓库的 docs 目录下同时镜像一份到团队的 Wiki。每次规则变更必须经过一次全员讨论至少要有一个真实案例支撑不能因为某个人觉得应该这样就加进去。2.2 审查的深度分级不是所有改动都需要同样的审查力度。一个简单的文案修改和一个核心交易链路的重构如果用同一套标准要么简单的东西被过度消耗要么复杂的东西被草草放过。我按改动风险把 PR 分成三档。第一档是低风险比如注释修改、文档更新、配置项增减这种只需要基础检查确保没有语法问题、没有敏感信息泄露就可以过。第二档是中风险比如新增一个普通接口、修改某条业务逻辑这种需要按完整清单逐项检查。第三档是高风险的比如涉及支付、用户数据、核心存储结构、并发逻辑的改动这种除了常规审查还要求至少两名资深工程师交叉 review并且必须有对应的测试用例覆盖。怎么判断一个 PR 属于哪一档我建议不要靠人肉判断而是写一个小的脚本根据改动文件路径和文件类型自动打标签。比如改了 money 相关的目录下的文件自动标为高风险。脚本可以把结果直接输出到 PR 的描述区域方便审查者第一眼就知道该用多大的力度去审。2.3 工具选型别一上来就上重型系统市面上的代码审查工具有很多从 GitLab Merge Request、GitHub Pull Request 自带的功能到 Gerrit、Phabricator 这种专门的审查系统再到各种商业化的平台。我的建议是不要一上来就上重型系统除非你们团队已经超过 50 人并且有专职的工程效率团队。open-code-review 的落地我建议用最轻的组合Git 托管平台自带 review 能力加命令行辅助工具加定时统计脚本。我们团队用的是 GitLabMR 的讨论、评论、审批能力完全够用。脚手架用自研的小脚本扫出一个 MR 里改动的文件清单和行数辅助判断风险等级。核心思路是让工具服务于流程而不是让流程服务于工具。如果你们的 code review 流程本身是乱的即使上一个再贵的系统也只会把乱放得更大。2.4 规则覆盖不到的角落规则是显性的但 code review 里真正值钱的部分往往是规则覆盖不到的角落。比如场景一改动只改了一行但这行在核心链路上。规则清单里不可能写每一行都要看但一个有上下文经验的审查者看到这行改动会本能地问一句这个调用方还有没有别的入口会不会影响别的流程这种基于全局理解的问题靠清单是筛不出来的。场景二新人提交了一个实现方式功能完全正确但使用了团队已经废弃的组件。如果审查者不了解历史背景不会觉得有问题。这就是为什么我做 open-code-review 时特别强调活文档——每次 review 中发现的非显而易见的问题都要求审查者顺手在评论里补一句背景然后沉淀到文档里。这两类情况说明code review 不能完全依赖一套静态规则规则只是底线真正的质量上限来自人的经验和视角互补。所以 open-code-review 的定位是用规则保底用人脑拔高。3. 实操全流程从提交到合入3.1 第一步提交者自检清单在 PR 提交给审查者之前提交者先过一遍自检可以省掉双方大量时间。这个自检不是高空喊话而是落到一个清单模板上。我用的 PR 模板长这样一段话说明这次改了什么为什么改上线后怎么回滚自查清单逐项打勾测试情况说明关联的 issue 链接。别小看这个模板它本身就是一道过滤器。如果一个人连为什么改都写不清楚那大概率他自己也没想清楚。自检清单里有几条是硬性的第一本地全部单测跑通第二涉及接口变更的curl 或脚本验证过第三改动涉及的日志都有对应的事件 ID方便链路追踪第四没有把调试用的临时代码提交进去。这个清单不是摆设。我在项目里写了一个 pre-push 的 Git 钩子在 push 之前会自动跑一遍单测和静态检查没过直接拦下来。技术上很简单就是.git/hooks/pre-push里写一段脚本判断测试命令的返回值。3.2 第二步审查者怎么读代码我见过很多人 review 代码的方式是打开 diff从第一个文件依次看到最后一个像读小说一样从头翻到尾。这种方式效率极低因为人脑在长时间阅读 diff 的时候注意力会快速衰减看到后面早就忘了前面在干什么。高效的审查顺序应该是这样先读 PR 描述搞清楚改动的意图和目标。然后看改动的整体范围哪些文件是核心逻辑哪些只是配套修改。先读核心文件的改动再往外围看。代码细节之后最后再看测试用例确认关键分支有测试覆盖。以我们团队遇到的一个典型情况为例。有个 PR 改了订单状态的流转逻辑表面上看代码很规整就是几个 if-else 块。但是如果只看 diff 而不理解业务上下文根本看不出问题。当时审查者先打开订单状态机文档对照状态跳转条件逐条验证结果发现有一个边界状态漏了判断会导致用户重复申请退款。这种问题只有在理解业务的前提下逐层思考才能发现。审查的时候我习惯把 diff 拉到本地用 IDE 打开看而不是直接在网页上看。因为网页上 diff 的上下文太少很多依赖关系看不出来。命令行里一条git diff加git log能快速看到这个文件的历史演进辅助判断这次改动的合理性。3.3 第三步评论规范和自动化辅助代码审查的评论区是团队技术文化最真实的体现。一个健康的评论区里讨论集中在技术上语气客观、有依据不会出现这写的是啥感觉不对这种主观模糊的表达。我在 open-code-review 里立了一条规矩每条评论必须有理有据。指出问题的同时要么给出具体的修改建议要么给出参考资料要么引用一条已有的规则。比如不能说这段性能有问题应该说这里在循环里调用了数据库查询数据量大的时候会产生 N1 查询建议改成批量查询这是相关文档链接。另外还配套了一个简单的小工具根据规则自动扫 PR 的常见问题。比如检查是否有调试代码残留、是否有硬编码的 IP 或密钥、是否缺少异常处理、是否在 for 循环里做了耗时的 IO 操作。这些是纯静态检查能覆盖的先让机器扫一遍人再专注看逻辑和架构。这个工具不用做得多复杂一个 Python 脚本加几条正则就能撑起最基础的能力。我在项目里就维护了一个ocr_check.py大概 300 行跑一次只要一两秒本地和 CI 都能跑。3.4 第四步与 CI/CD 的联动code review 不能只靠人肉。在我搭 open-code-review 的时候第一个联动的就是 CI 流水线。规则很简单静态检查、单元测试、构建这几关不过PR 不允许合入。这一步在 GitLab CI 里就是一段配置的事但效果立竿见影。整个合入流程跑一遍推代码 - 触发 CI 流水线 - 跑静态检查和单测 - 通过后自动通知审查者 - 人工审查 - 至少一个 approve - 流水线允许合并。每条规则都能落到可检查的环节上。人工无法自动检查的部分比如业务逻辑和架构设计才留给审查者。这里有个团队协作上的细节要注意CI 的检查项不能太苛刻否则频繁误报会让所有人对流水线失去信任。我建议一开始只配置最刚性的检查比如编译不过、测试失败、明显安全问题。随着团队接受度提高了再逐步加入更严格的检查。4. 常见问题与排查技巧4.1 同事总说没时间 review是真没时间还是不想审这是我在落地过程中收到最多的抱怨。拆开来看一般有两种情况。第一种是确实忙任务排得满满当当临时插进来一个 review 请求确实会打断手头的工作。这种情况的解法是固定审查时间段。我们团队约定每天下午四点到五点是集中 review 时间有 PR 的人在这个时间段优先处理。其他时间收到 review 请求如果手头有紧急工作可以直接拒绝并在群里说一声明天下午 four 点。第二种是觉得 review 别人的代码没有价值感认为这是在耽误自己的时间。这种情况靠讲道理没用要让对方在 review 中获得正向反馈。我的做法是在月度技术分享会上把 review 中发现的好问题和典型案例拿出来公开肯定提意见的人。几次之后大家会发现善于 review 也是一项硬技能跟写代码一样体现水平。4.2 反馈被当成挑刺怎么办团队里关系比较敏感的时候代码审查很容易触发矛盾。一个新人被老员工连提七八条意见哪怕每条都有道理心理压力也会很大。解决这个问题我用了两个方法。第一是培养提意见的礼貌成本意识。评论里先说明这个改动好在哪里再提出问题。比如整体设计清晰异常处理也到位但这里有一个边界情况没覆盖申请退款状态为已拒绝时这个判断会直接跳过建议补一个分支。第二条是在规则里约定任何 review 讨论不允许出现人身评价词比如简单的东西都写不好这种话一旦出现直接警告。有一次我们团队新来的一位同事写的代码被提了十几条意见我私下找他聊了一次。他的顾虑其实不是意见本身而是担心大家觉得他能力不行。我给他看了新人期的历史 PR他自己也明白这是正常过程心态就调整过来了。文化这个东西需要靠一次次沟通养起来。4.3 PR 太大没人愿意审怎么拆早期我们团队经常出现一个 MR 改了几十个文件、几千行代码看起来头晕审查者根本不知道从哪下手。这种巨型 PR 是 code review 的头号杀手。解法不是在 review 阶段硬啃而是在提交之前就拆。我在团队里立了一条规则一个 PR 的改动量原则上不超过 400 行最多不超过 800 行超过的必须拆成多个有先后依赖关系的 PR 按顺序提交。这条规则一开始被抵触认为拆 PR 增加工作量。但实际做下来发现拆 PR 的过程本身会强迫提交者按功能模块整理思路反而能提前发现不少设计问题。有一种情况例外纯机械改动比如格式化、重命名、批量替换。这种 PR 虽然改动行数很多但风险很低我允许一次性提交但必须在 PR 描述里写明本 PR 无逻辑改动可抽查。4.4 规则被绕过approve 变成形式怎么办还有一种常见问题是规则明明写了但项目快上线了经理在群里催赶紧 approve结果有人顶不住压力看都不看就点了同意。这种事出现一次规则就废了一半。我的处理方式是分两层。第一层是技术上兜底高风险类型的 PR 在 GitLab 里配置了审批规则必须指定两位核心维护者 approve 才能合入其他人点了也不算数这一层由工具强制。第二层是流程上留出特批通道。如果确实因为上线窗口等原因需要带病合入必须走特批流程写清楚风险、明确后续修复计划、指定跟进人。特批的 PR 会被特殊标记下次回顾的时候单独复盘。特批通道的存在不是为了方便跳过规则而是让破例这件事变得有成本、可追溯。一旦特批次数多了复盘会自然会让团队反思是不是规则太严还是计划安排不合理。这种机制反而保护了规则的严肃性。4.5 小型团队或个人项目也要搞 code review 吗很多独立开发者和两三人小团队的开发者会问就我一个人写代码code review 搞不起来怎么办我的看法是单人项目不需要传统意义上的 peer review但可以做自审 review。具体做法是代码写完之后不要立刻提交放一晚上第二天用 review 的心态重读一遍 diff。人在刚写完代码时对自己的问题是有盲区的隔一天再读很多不合理的地方就会冒出来。配合静态检查工具和好的测试用例单人项目也能达到不错的代码质量。另外如果有开源社区完全可以借助社区的力量——在开源项目上提 PR会被维护者 review那本身就是一次高质量的审查训练。5. 落地 open-code-review 的具体步骤5.1 第一个月先立规矩再建清单不要指望一步到位。第一个月我做的最重要的事情就是建立规则清单。当时花了两天时间把团队过去半年线上事故和返工案例全部过了一遍归纳出共同的教训形成了初版 P0 规则。这个动作的价值在于规则不是我拍脑袋编的每条都是从真实教训中提炼的这让它在推行的时候更有说服力。然后我把规则文档发给团队所有人开了一次评审会逐条讨论。讨论中删掉了几条大家觉得没必要的也新增了几条别人提出来的。定稿后的规则文档就是 open-code-review 的基石。5.2 第二到三个月用数据说话边跑边调规则落地之后我开始做数据统计。我用一个简单的脚本定期拉取 Git 平台上的合并请求数据和讨论数据统计几个指标平均首次响应时长、平均合并周期、每个 PR 的评论条数、被反复要求修改的 PR 数量。盯着这些数据做了两个月我发现一个有意思的现象平均首次响应时长从最初的 28 小时降到了 6 小时但每个 PR 的评论条数反而变多了。这说明大家不是没时间 review而是之前没有明确的时间和流程来驱动。数据是最好的说服工具团队里原本反对流程的人看到数据后也认可了这套做法。5.3 复盘会把 review 变成团队学习机制每个月底我组织一次 code review 复盘会但不是普通的工作总结会。我们把当月 review 中发现的高质量案例整理出来选两到三个典型在会上重新过一遍。一个看看当时的问题是怎么被发现的一个看看如果没被发现线上会发生什么。这样做的目的是让会 review成为一种可学习的经验而不只是某几个人的天赋技能。复盘会还有一个作用就是收集规则之外的隐性知识。有一次复盘我们发现一个性能问题不是靠规则发现的而是因为审查者恰好对这个领域的框架底层比较熟悉。这种靠运气才能撞上的问题本质上不应该只靠运气而应该沉淀成文档和用例。于是我们就补了一条路线核心功能的性能测试场景要写进测试代码里而不是每次靠人肉思考。整个过程走下来我的一个明显感受是code review 不是一个工具也不是一套规则它本质上是一个团队如何对待代码质量的价值观的体现。open-code-review 这个名字重点是 open——规则开放的团队代码质量不会太差团队成员之间的信任也会慢慢建立起来。