ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

如何把Code Review从走过场变成团队成长引擎?

如何把Code Review从走过场变成团队成长引擎? 1. 为什么我把Code Review从走过场改成了开放审查先说我这边的情况。团队不大算上前后端和测试不到二十人代码量却不小。早先也搞过Code Review每周五下午拉个会投影仪一开主讲人从头到尾过一遍 diff。刚开始大家还愿意看看逻辑、提提意见几周之后就变成了你看着没问题就过吧——不是不想认真是真的没法认真。diff 在投影上跳得飞快细节根本看不清再加上评审的人手上都有活心思不在那四十分钟里面最后 Code Review 沦为了一个代码朗读会所有人都在等散会。后来我意识到问题不在人在机制。传统的 Code Review 天然带有一种审查的对抗感——提交的人觉得自己是来交作业的评审的人觉得自己是来挑错的。这种心理姿态一旦形成讨论就会变形提交者倾向于把代码写得看起来没问题评审者则倾向于提一些不痛不痒的问题来证明自己看过。两边都在表演性能、可维护性、边界条件这些真正重要的东西反而没人关心。所以我把流程改了不再叫它 Code Review而是用 open-code-review 的思路重新设计了一整套流程。所谓 open不光是代码对所有人开放可见更重要的是审查过程、讨论细节、决策理由全部开放谁都能参与、谁都能提问、谁都能从别人的 diff 里学习。这个改动看起来只是换个名字实际操作起来差别非常大。结果也印证了这一点。实行了一个季度之后线上的 bug 数量下降明显更关键的是团队里新人的成长速度快了不少——他们每天都能看到老手之间怎么互相 review、怎么讨论设计取舍这比任何培训都直观。这篇文章我就把这套流程里最值得复制的部分拆开讲清楚从机制设计到工具配置再到踩坑记录给准备做 Code Review 或者想改进现有流程的团队一个参考。1.1 走过场式审查的三个典型症状如果你不确定自己的团队 Code Review 有没有出问题可以对照这三个症状。第一个症状是评论数量断崖式下降。流程刚推行的时候一个 MRMerge Request下面至少有五到十条评论三个月之后大部分 MR 只剩一两条很多直接是 LGTMLooks Good To Me。别高兴这不是大家水平提高了而是疲劳了。一旦审查变成了过一眼就放行连提交者自己都会变随意反正写错了也有人看不出来。第二个症状是评审集中在代码风格上。如果 review 评论里最多的是这里少了个空格变量名改成 xxx 更清晰这行超过 80 字符了说明流程已经在空转。风格问题应该交给 linter 和 formatter 自动处理人肉 review 的核心价值应该在逻辑、架构、边界条件、安全性这些机器不容易判断的地方。第三个症状是合入依赖谁催得急。一个 MR 在队列里挂了三天没人理但只要提交者在群里 一下或者在 IM 上私聊十分钟内就有人点 Approve。这种靠人情驱动的审查完全失去了制度意义——它不再是代码足够好才合入而是不好意思不给你过。凡是出现这三种情况的团队Code Review 基本已经死了挂着的只是个仪式。1.2 开放审查到底开放的是什么我理解的 open-code-review 不只是把仓库设成公开可见它包含了三个层面的含义。第一层是代码开放。所有参与者都能看到完整的 diff包括上下文、依赖改动、测试覆盖情况。这意味着审查不只是一个 Reviewer 和提交者之间的对话而是整个团队都可以参与的技术讨论。特别推荐让刚入职的新人旁听甚至发言他们的问题往往最基础但也最容易暴露文档和命名上的缺陷。第二层是过程开放。评审意见、修改记录、最终决策理由全部留痕。选 A 方案不选 B 方案把原因写下来哪怕只是一句话。这些东西一个月后回头看就是团队的技术决策日志比任何 wiki 都真实。第三层是心态开放。这是最难但最关键的一层。提交者要把自己的代码当成我提交的一个方案而不是我的作品Reviewer 要把批评当成我们在讨论怎么让代码更好而不是你写的东西有问题。心态调整到位之后评论的语气会自然从你这个 bug 没处理变成这边有个边界情况需要想想我们一起来看下。2. 开放审查的前置条件先解决愿不愿意审再谈会不会审很多团队在推 Code Review 的时候第一反应是选工具——用 GitHub 还是 GitLab要不要上 Gerrit能不能接 CI。这些当然重要但如果团队里没有人愿意认真看别人的代码再好的工具也是摆设。所以我建议顺序反过来先把人的问题解决掉再谈工具和流程。2.1 团队共识比工具更重要怎么让大家愿意审不愿意审的背后通常是两个原因没时间或者觉得不关我事。没时间是效率问题相对好解决。我的做法是把 Code Review 写进迭代排期每个 MR 的审查时间按代码量动态分配——改动超过 500 行的 MR给 Reviewer 留一个小时的整块时间而不是让他见缝插针。有些团队会担心这样拖慢节奏实测下来其实不会。因为审查质量上来之后合入后返工的情况大幅减少算总账反而是赚的。觉得不关我事是心态问题要麻烦一些。我的破局点是强制跨模块审查。前端的人必须审后端核心逻辑QA 的人可以审开发者的单测覆盖。这么做有双重收益审查者能从外部视角发现内部人看不见的问题同时也让每个人意识到——代码不是某个人自己的事是共同维护的资产。这里有个容易踩的误区不要用绩效考核去倒逼审查。我们曾经试过把Review 数量计入 OKR结果大家开始刷评论一堆建议加个注释建议抽个函数这种没营养的评论满天飞。后来我把指标改成了Review 是否帮助提交者发现了至少一个实质问题情况才好转。2.2 评审工具与自动化配置的落地经验人的问题解决之后工具的作用才开始显现。以我们用的 GitLab 为例核心配置就那么几项但每项都很关键。第一个配置是权限规则。我的建议是主干分支直接锁死任何人不允许直接 push只能走 Merge Request。合并权限至少需要一位 Maintainer。不要给所有人 Maintainer 权限代码库需要有个最后的兜底者。第二个配置是合入检查。MR 必须满足三件事才能点 Merge至少一位 Reviewer 同意、CI 全绿、冲突已解决。这个用 Merge Request 的 Approval Rule 设置一下即可。第三个配置是自动标签。按改动范围打上 frontend/backend/test 标签让对应领域的维护者能第一时间捞到跟自己相关的 MR。safe.yaml里我加过一个实用的规则超大 MR 自动标记。超过 800 行改动的 MR 会带一个large-change标签提醒 Reviewer 重点关注。这个数字可以按团队情况调整但一定要有这个阈值后面我会细讲为什么。# 基于 GitLab Code Quality / Approvals 的简化配置示例 rule: - name: require_reviewer approvals_required: 1 scope: merge_request - name: block_large_change action: warn condition: size: operator: greater_than value: 800CI 里面的静态检查也要配置好。我强烈建议把代码风格检查ESLint、Ruff、golangci-lint 之类做进流水线不通过直接 fail。这能把这行太长缩进不对这类琐碎评论从 Code Review 里彻底消灭让人的注意力释放出来去关注真正重要的东西。同时单测覆盖率阈值也得设低于某个数值直接不让合入这是硬性红线不能商量。3. 让 Open Code Review 真正跑通的四条链路工具和心态是地基在这之上要有一套可执行的流程。我总结下来一套运转良好的开放审查流程至少需要四条链路——提交、审查、反馈、闭环。每条链路都有对应的规范和细节缺了任何一条整个流程都会有漏洞。3.1 提交侧MR 描述模板与提交信息规范开放审查的第一步是提交者把背景讲清楚。很多人觉得提 MR 就是把代码贴上去描述随便写两句就完了这是最大的误区。Reviewer 在没有上下文的情况下看代码就像进电影院不看片名不介绍直接从中间开始看他很难进入状态。我团队里的 MR 模板包含四个固定部分背景、改动方案、验证方式、影响面。不要求长但四个部分必须有内容。背景写三句话让 Reviewer 知道是为了修 bug 还是加功能改动方案说明思路和备选方案哪怕只有两行验证方式写我跑过什么测试、有没有在本地复现影响面写这是否会影响其他模块是否需要联调。## 背景 修复用户反馈的订单导出失败问题原因xxx ## 改动方案 - 导出模块中增加重试机制 - 失败时记录日志并抛出自定义异常 - 备选方案同步改定时任务但考虑到范围协变暂缓 ## 验证方式 - 本地复现原 bug并验证修复生效 - 单元测试新增3条用例全量通过 ## 影响面 - 涉及导出服务不影响其他模块 - 需要 QA 回归一次订单流程提交信息也要规范。这是一个看起来无关紧要、实际影响巨大的细节。很多人提交信息随手写fix bugupdate code等三个月后查为什么改了这一行的时候完全查不到。我们统一要求遵循语义化提交格式type(scope): description。比如fix(export): retry when session expires一行话把改动意图说清楚。这个规则配合 git log 就是最朴素的代码文档。3.2 审查侧时间窗口与节奏管理Code Review 最怕的事情是拖延。一个 MR 挂两天没人审提交者只能先去写新需求等他回来处理 review 意见的时候上下文已经丢了改起来效率极低。所以节奏比效率更重要。我定了一个硬性规则MR 必须在 24 小时内获得第一轮反馈。如果实在来不及完整审至少要回复一句收到了明天上午出意见让提交者知道有人在跟进。24 小时的设定不是拍脑袋——一个开发者对刚写完的代码的记忆清晰度在 24 小时内是最高的超过这个时间他需要重新读一遍自己的代码才能理解当时的思路沟通成本立刻翻倍。另外我给不同规模的 MR 设了不同的审查策略。小改动少于 100 行十分钟内快速过一遍重点看逻辑和边界中等改动100 到 400 行需要完整审查可能还要拉出相关代码一起看大改动超过 400 行不能硬审可以拆成多个小 MR或者至少拆成逻辑块逐个过一次性看 1000 行 diff 是无效且痛苦的。3.3 反馈侧评论写法、冲突处理与升维机制Review 意见的写法直接影响接收者的心态。我强调过一个原则对事不对人具体不模糊。举个例子与其评论这个函数的命名有问题不如说getUserList这个名字太宽泛了这里实际上是获取已激活用户建议改成getActiveUsers。前一种说法像是在评价一个人后一种是在讨论代码本身。很多冲突的苗头都源于表述方式。我自己写 review 意见的习惯是至少说清楚现状是什么、建议改成什么样、为什么三要素。如果只是丢一句这里可以优化等于没写。Reviewer 要对自己的评论负责被评论者也应该有渠道表达不同意见。当意见不一致的时候我们的做法是小问题评论区讨论解决大问题直接拉会三五个相关人线上或线下讨论不搞拉锯战。还有一个经常被忽略的角色是提名 Reviewer。提交者在创建 MR 时指定一个主要负责人但要留一个口子——只要对代码库感兴趣的人都可以进去看、去评论。这就是开放的体现。核心 Reviewer 负责最终拍板外围评论提供多元视角这样既不会责任不清也不会变成少数人的任务。3.4 闭环侧问题追踪与度量不搞审了就忘Code Review 最大的浪费是讨论完就结束了后续没有跟进。Reviewer 提了三个问题提交者改了两个第三个觉得麻烦没改也没说明原因。这种事发生过太多次了必须用机制堵住。我们的做法是在 MR 的 checklist 里加上一条所有 review 意见必须对应 resolution已修复/已解释/后续跟进。已解释的要把理由写在评论下面后续跟进的必须给一个 issue 链接。这样我知道有问题但暂时不改就有明确的责任归属和追踪入口而不是从裂缝里直接漏下去。度量方面我每个季度会看几个核心数据MR 平均反馈时间、平均审查轮数、每 MR 有效问题数、变更后 bug 率。特别注意有效问题的定义——我们只看确实发现问题并进行了代码修改的评论那些建议加注释之类的无效评论会被自动过滤掉。不说假话这些数据很大程度上改变了我对团队状态的判断比拍脑袋准得多。4. 我推行 open-code-review 时踩过的坑与排查过程流程跑了大半年踩过的坑不少其中四个最典型也可以说是四个不同的维度。分拆开讲一下希望各位不用再走一遍。4.1 坑一无差别全员催审反而拖垮了节奏刚开始我非常理想化认为代码库里的每个 MR 都应该尽快被 review于是设置了全员提醒——每个新 MR 创建后CI 机器人在群里艾特所有人来审。效果怎么样没有效果反而更糟了。因为所有人等于没有人,大家看到艾特别人,就默认别人会去处理。再加上那些跟自己的工作模块完全无关的 MR,干擾性很强时间一长大家对群通知彻底免疫有时候连自己的 MR 被反馈了都没看到。排查下来我发现,问题出在通知本身没有做定向。真正高效的触发路径不是所有人周知,而是只有相关的两三个人知道。于是我把机器人改成了精准通知:MR 创建时,只艾特提名 Reviewer 和相关模块的维护者;如果过了 12 小时没有动静,再补发一条提醒。改动很小,反馈速度却快了好几倍。这个坑的本质是流量不等于注意力,推送给你的消息如果没有筛选,最后就会被全部过滤掉。4.2 坑二评论语气导致的对抗情绪有一次两个组员因为 review 评论吵起来了。提交者觉得自己被冒犯了Reviewer 觉得自己就事论事。我先把两个人拉通说了开诚布公聊一下各自的感受然后发现问题的核心不是代码是一句话的具体措辞这个写法太低级了应该用 xxx。这句话本身有对的部分——建议是对的,但太低级这个前缀完全没必要,它攻击的不是代码,是提交者的能力。这件事之后我定了一个规矩禁止在评论里使用评价性语言只能描述问题和建议。太差低级这都不懂这类词一律禁止。备选说法是这个地方如果用 xxx 实现会更简单/性能更好你觉得呢。评论规范写进团队文档里,新成员入职第一周就要读完。这不是说大家说话要小心翼翼,而是要找对讨论的靶子——我们的目标是代码,不是人。4.3 坑三把 Code Review 当成了代码检查工具有一段时间,团队里部分开发者陷入一个误区:什么都要拿到 MR 里来 review。README 改了十几个字也要提 MR,配置文件调了个参数也要发出来。这看起来是流程执行得很彻底,实际上是把 Code Review 用错了地方——用来做所有变更的审批工具,而不是代码质量的把关手段。排查这个问题的過程有点意思。我先去翻了最近一个季度的 MR 记录,发现有接近 20% 的 MR 改的是纯文档、纯配置、纯格式化内容,这些完全不需要走完整审查流程。后来我们给这些低风险变更开了一条绿色通道:改动范围仅限 docs/、config/ 下的文件且不影响逻辑的,可以直接合入主干,只需要 CI 过就行。这样把 Code Review 的带宽从琐碎中解放出来,大家的平均 review 时长一下子降了下来,核心代码的审查质量反而明显提高。4.4 坑四审查范围过大导致注意力稀释这也是我们踩过很深的一个坑。开始的时候,有人提了一个改动范围很广的 MR,差不多 1500 行,横跨前端、后端和测试代码。我自己去审,看了半天,发现看到后面已经完全记不住前面改了什么,更别说不同文件之间的逻辑关联了。这种审查只是走马观花,底线是只能发现一些低级问题,真正的架构隐患完全被淹没在大范围的 diff 里。解决之法是两条腿走路。一条我们已经讲过大 MR 自动标签,超过 800 行就警告;另一条是从源头控制,大功能必须拆成小 MR 逐步合入,每次只改一个逻辑点。这时候有仔细的读者会问,有些功能确实牵一发动全身,怎么办?——我的回答是:那说明前置设计没到位,改动边界没有理清。这时候不应该硬拆,而应该先把重构单独抽出来,再做功能改动,两步走,每个 MR 的职责就清晰了。5. 把开放审查变成习惯的几套可复制机制流程和规范坚持执行半年之后,Code Review 已经不再是负担,反而成了团队里最有价值的技术活动。这个阶段出现了一个新的契机——不用再靠制度推着走了,可以开始琢磨怎么让这一套东西沉淀成习惯。下面三套机制是我们试下来最有效,也是open精神发挥得最充分的地方。5.1 Review 轮值表与备份人机制为了让每个人都有机会深度参与评审,我们引入了轮值表。每周安排一个首席 Reviewer,负责当天所有新 MR 的初步排查和分流。他的职责不是自己把所有代码都审一遍,而是——先过一遍 MR 列表,剔除低风险项,把需要完整审查的 MR 分配给相关领域的人,并且他是整个流程的兜底者:如果某个 MR 超过半天没人接手,他去顶上。这个机制有个隐藏收益:负责轮值的人会在那一周快速了解代码库的全貌,因为他必须浏览所有新 MR 的标题和描述。对一个初级开发来说,这是最快熟悉系统的方式之一。同时我们给每个模块都设了备份人,主 Reviewer 请假或不在线的时候,备份人能立刻接手,不会出现人不在,MR 就卡住的死锁状态。这个备份机制在重要节点极其重要,比如发布前的一个紧急修复,如果唯一能审核的人正在休假,整个发布都得陪着等。5.2 轻量级自检清单把最常犯的错前置化如果你反复在 review 中看到同样的问题,说明问题不在提交者的注意力,而在检查机制。我们花了几个月的时间,把 review 评论里高频出现的几类问题汇总成了一张自检清单,提交者在提 MR 之前必须过一遍。这份清单贴在仓库根目录的PULL_REQUEST_TEMPLATE.md里,没人能跳过。清单内容不多,就六条:是否处理了全部输入异常?是否考虑到空数据/极端值情况?错误信息是否包含足够上下文?是否添加了必要的日志?是否新增了对应的单测?是否更新了相关文档?每条后面跟一个复选框,提交者在描述里勾选。谁提交谁负责,Reviewer 看到有没勾的项会直接把这个 MR 打回去。5.3 从审查到技术复盘开放审查的进阶形态当 Code Review 做顺了之后,它可以自然演化成不固定的技术讨论社区。现在我们每周做一次review 复盘会——不审查新代码,而是把过去一周内讨论最激烈、争议最大的 2 到 3 个 review 话题拿出来,重新完整过一遍。会上默认没有权威:初级开发可以质疑架构师的方案,只要你的论点站得住。这样的形式比任何技术分享会都有意思,因为全是最真实的业务场景和最没有套话的技术讨论。说句实在话,当初改这个流程的时候,我也没想到最深远的收益不是 bug 变少,而是团队里的技术讨论氛围完全变了。代码从一个一个孤立的任务,变成了一面大家可以天天照的镜子。你在 review 别人的代码时学到的东西,远比自己埋头写代码学到的多;而你的代码被别人 review 时获得的提升,也远比一个人反复自查来得快。这就是开放的价值。
返回列表