ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

open-code-review实战:从审查规范到团队协作的完整指南

open-code-review实战:从审查规范到团队协作的完整指南 提到 code review很多人第一反应就是走个过场代码写完丢给同事看一眼回一句 LGTM合入完事。我刚工作的前两年也是这么干的直到一次线上事故把锅甩到某个 review 通过的提交上才意识到这玩意儿根本不是流程负担而是一个团队最后的防守线。后来我在团队里牵头搭了一套更开放的代码审查机制也就是标题里写的 open-code-review——不把它当流程工具而是当技术基建去运营。这篇文章就把我实践的完整思路、操作步骤、踩坑记录都整理出来适合正在被 review 弄得焦头烂额的开发、准备给团队搭审查规范的 tech lead以及对代码质量有执念的独立开发者。1. 先拆一拆open-code-review 到底在整什么1.1 为什么非要把审查加上open这个前缀很多人觉得代码审查就是找人看代码这个理解没错但它漏掉了最关键的一层审查的透明度。传统或者说默认状态下的 review 往往是点对点的——你提交、指定一个人审查、两人私聊式地你来我往其他人根本不知道这段代码为什么被改、为什么被拒、为什么最终以这种形式合入。这种闭门式审查最大的问题在于知识和决策都被锁在少数人脑子里团队其他人只能通过 git log 猜。open-code-review 的核心是把整个审查过程摆在台面上审查意见公开可查、评审结论有据可依、任何成员都可以参与讨论。我搭这套机制的时候并不是为了搞什么仪式感而是切切实实吃过亏。有一次一个老同事改了一段核心链路他找另一个资深工程师看了一眼两人私聊里确认了几点然后合入。三周后线上的诡异问题一路排查下来根因恰恰是那几次私聊里没写进 commit message 和 MR 讨论区的决策。如果当时的意见是公开留在 MR 里的排查的人根本不用重新把推理过程走一遍。所以 open 的第一个含义是信息公开。小到一条留言、大到一次设计取舍全部沉淀在 MR/PR 的时间线上。open 的第二个含义是参与开放。不再限制必须是指定 reviewer 才能说话任何有上下文的人都可以上来提一句哪怕只是一句这里是不是少了边界判断。open 的第三个含义是规则开放。审查标准不是某个 leader 脑子里的一套隐性规则而是写成文档、进 checklist、人人都能指出你没按标准来。这三点做扎实之后代码审查的价值会发生质变——它从一次质量检查变成了团队知识的持续沉淀渠道。1.2 公开代码审查能带来的隐性收益很多人会问公开审查会不会让写代码的人压力很大我的实际体验是刚开始会习惯之后就真香了。因为公开意味着写代码的人会更谨慎地组织自己的提交、更认真地写描述和注释减少反正有人会看我先推上去再说的烂提交。这种心理变化本身就是质量的提升。从新人的角度看open-code-review 是成本最低的学习入口。一个新成员想了解某个模块是怎么回事与其去翻几十个 commit 拼凑上下文不如直接去翻这个模块最近几个大 MR——设计动机、备选方案、踩过的坑全在里面。我团队里有两个初级工程师就是靠每天花半小时翻历史 MR 快速上手的比看任何文档都快。还有一个容易被忽略的收益责任边界变得清晰。当审查意见和结论都公开之后这个 bug 是因为 review 没看出来这类甩锅争论会大幅减少。因为整个过程有据可查哪条意见提了、哪条没提、哪条被忽略了一清二楚。不再是谁红谁有理而是看事实。这里要说明一点open-code-review 和 code review 并不是对立关系前者是后者的一种组织和运行方式。如果你所在的团队已经有了审查流程你要做的不是推翻重来而是在现有基础上把信息公开化、参与扩大化、规则显性化。2. 把审查做顺的前提提交规范与规则约定2.1 小步提交一切 review 体验的起点公开审查机制有一个硬前提如果做不到后面所有环节都会很难受提交必须够小。一个 MR 改了 40 个文件、涉及 3 个模块、混着重构和新功能哪怕是再资深的审查者看 10 分钟也会大脑宕机最后只能给出一个流于形式的 LGTM。这不是审查者偷懒而是人类工作记忆的物理极限。我给自己和团队定的标准是一个 MR 尽量控制在 200 到 400 行以内改动文件不超过 10 个聚焦单一意图。如果改动超过这个量级必须拆分。拆分的依据不是按文件来分而是按逻辑边界来分。比如一次升级涉及接口变动、实现替换、测试补全那就拆成三个 MR先改接口并做好兼容再换实现最后补测试。每个 MR 单独可合入、单独可回滚。小步提交的另一个好处是 review 时速显著提升。我实测过一个 200 行以内、上下文清晰的 MR认真看一遍加回复意见大约需要 15 到 20 分钟。而一个上千行的 MR往往需要两小时以上而且看得越久注意力越差漏掉的 bug 越多。所以小提交不是磨叽是效率。这里有一个实操技巧在项目里强制推行 commit message 规范把意图写清楚。我团队用的模板是:type(scope): subject BLANK LINE bodytype 用 feat、fix、refactor、test、docs 这些约定式提交的关键字scope 写模块名subject 一句话说明意图body 里写背景和 trade-off。目的不光是好看而是让 review 的人拿到 MR 的第一时间就能判断这个改动要解决什么问题不用从 diff 里反推。2.2 建立一份团队认账的 Review Checklist审查标准如果只是认真看那等于没标准。不同人眼里的认真偏差巨大有人盯着缩进和命名有人只关心并发安全结果就是该看的关键点没人看不该看的地方吵了一堆。为避免这种混乱我把审查拆成几条明确的检查维度做成 checklist 放进 MR 模板里。我的核心检查维度有五条。第一是正确性这个改动逻辑上对不对边界条件是否处理错误路径是否覆盖。第二是安全性涉及输入的地方有没有校验权限判断是否到位敏感信息有没有泄露风险。第三是性能有没有明显的循环嵌套、N1 查询、不必要的内存拷贝。第四是可维护性命名是否表意函数是否过深是否需要注释的地方有没有注释。第五是测试覆盖新增逻辑有没有对应测试改动的行为有没有被测试锁定。checklist 不是用来机械打勾的它的作用是给审查者一个被遗忘提醒。我自己在 review 的时候会先按这五条过一遍再针对具体模块补充专项检查比如涉及支付的要额外看幂等和金额计算涉及并发的要额外看锁粒度。有一点很重要checklist 不是一成不变的每踩一次大坑就往里面加一条。我们团队的第一版 checklist 只有三条后来经历过一次缓存穿透事故加了缓存 Key 是否设置过期时间和空值保护经历过一次数据一致性问题加了多步操作的事务边界是否清晰。当审查规则是从真实事故里长出来的团队成员对它的认可度会很高。2.3 审查角色与权责划分小团队通常不搞复杂的角色体系但至少要区分两类角色作者和审查者。作者对代码负责负责讲清楚改动原因、回复每条意见、必要时调整方案。审查者不是质检员更像是结对伙伴目标是把代码改得更好而不是挑刺挑到别人怀疑人生。在多人的团队里我还设置了 Maintainer 角色负责最终合入。Maintainer 的职责很具体确认所有讨论已闭环、检查 CI 状态、必要时叫停明显有问题的方案。这个角色不能兼任该 MR 的作者否则就失去了独立把关的意义。审查者数量的设置上我的经验是2 个足矣。太多审查者会导致责任分散——每个人都觉得别人会认真看结果没人认真看。太少则容易形成盲区。2 个人既能覆盖不同的关注点又不会让讨论成本过高。权限分配也要提前想清楚。公开审查不等于所有分支对所有人开放写权限那会乱套。我的做法是主干分支只有 Maintainer 有合入权其他成员可以参与任意 MR 的讨论但写权限按模块划分。这样既保证了 open 的参与度也守住了安全边界。3. 实操过程一次标准的 open-code-review 怎么跑完3.1 从创建 MR 到最终合入的生命周期既然要给大家一个可以直接抄作业的流程我就把一次完整 MR 审查的每个阶段捋一遍。第一步是创建 MR 之前的自查。作者需要保证本地分支通过全部相关测试保持 rebase 到目标分支最新且 MR 描述里说清楚三件事改了什么、为什么改、测试验证结果。这个自查环节省掉了审查者大量低质量提问。第二步是发起 MR 并提交审查。在 GitLab 或 GitHub 上创建 Merge Request 或 Pull Request指定 2 名审查者。MR 描述使用模板贴需求链接列出改动文件清单标注哪些是重点需要仔细看的。如果是修复 bug附上复现步骤和修复前后的行为对比价值极高。第三步是审查者执行审查。审查者先看描述和 diff 结构再逐文件过代码。发现问题的直接在 diff 行内留言把问题说清楚最好给建议示例。这里推荐一个技巧按严重程度给意见分级。P0 是必须修才能合入的问题比如数据错误、安全漏洞P1 是强烈建议修比如明显设计缺陷、性能隐患P2 是可改可不改的优化建议。分级之后作者能快速判断优先级审查者也不用每条意见都执着到底。第四步是作者回复与修改。作者对每条意见给出明确反馈采纳、拒绝或部分采纳。拒绝的时候要给出理由不是对抗而是解释。修改完成推送新 commit然后逐一 对应审查者请求重新审查。第五步是条件满足后合入。我建议开启同意后合入 流水线通过 至少 1 个 Maintainer 批准的保护规则。合入方式用 squash merge把一个 MR 的多个修复 commit 压成一个保持主分支历史干净。这个流程跑熟之后一个常规功能 MR 从创建到合入的时间控制在 2 到 4 小时内效率并不低。3.2 工具配置GitLab / GitHub 实测怎么开我团队主力用的是 GitLab这里分享一下关键配置。如果你用 GitHub对应的功能也都能找到。先说分支保护。在 GitLab 的 Settings - Repository - Protected branches 里把主分支设为受保护勾选Allowed to merge仅 Maintainer勾选Allowed to push仅 Maintainer。这样一个 MR 没有审批就无法合入从机制上就堵住了顺手推主分支的坏习惯。再说 MR 审批规则。GitLab 的 Merge request approval rules 可以配置当 MR 更新时重新触发审批。我觉得这个必须开。否则作者改完一轮 code之前的批准还挂在那边等于审查白做。重新触发审批能让审查者对最终版本负责。还有一条配置容易被忽略Squash commits。在 GitLab 的 Merge request 设置里勾选强制使用 Squash 合并选要求所有提交消息遵循约定式提交。这样每次合入主分支的提交都自带规范格式git log 看起来赏心悦目出问题也好定位。GitHub 这边对应的是 branch protection rules在 Settings - Branches 里添加规则勾选 Require a pull request before merging设置 required approvals 为 1 或 2勾选 Dismiss stale pull request approvals when new commits are pushed再勾选 Require status checks to pass before merging。和 GitLab 的逻辑一一对应。如果你用的是 Gerrit 或者 Phabricator核心思路也一样强制走审查、按阶段更新、审批在最新版本上有效。工具可以换原则别丢。3.3 让审查意见高质量的几个细节配置只是骨架真正让 open-code-review 跑得好的是细节处理。先说行内注释。我强烈建议意见直接挂在具体的代码行上不要只写在 MR 总评论区。行内注释带着上下文作者一眼就知道对应哪段代码沟通成本直接减半。再说代码块建议。在 GitHub 的 review 界面可以插入 suggestion 代码块作者点一下就能应用修改。在 GitLab 的 13.x 之后的版本也支持代码建议。这个功能最大的价值是消解了审查者在给命令的那种压迫感——你不是在说你写错了而是在给这样写更好。还有一个习惯值得培养审查的时候标记非阻塞。当一个意见不影响合入但值得记录时明确写上 Non-blocking / 可后续处理。这能减少很多无谓的来回拉扯。作者看到非阻塞标记知道可以合入后处理就不会卡在流程上。最后是 MR 讨论区的使用。我要求团队的 MR 里必须有验证记录区域作者写明本地测试跑过什么、覆盖率有没有变化、有没有手动验证的场景。这就避免了审查者反复问你测过没这种低效问题。4. 踩坑实录与排查技巧4.1 审查意见发出去没人理怎么办这是我团队最初遇到的最恼火的问题。reviewer 提了一堆意见作者隔了两天才回一句哦我改一下或者干脆不回复直接合入。后来我们定了两条硬规矩才解决。第一条MR 合入前必须清理所有开放讨论。技术上讲GitLab 和 GitHub 都支持在合入时检测未解决的 conversation但默认不强制。我在项目里直接开启所有评论必须 resolve 才能合入让未回复的对话成为流程阻塞项。这一条最有效因为它是机制层面的兜底。第二条作者超过 24 小时未回复审查意见Maintainer 可以主动把 MR 标记为 WIP 或直接关闭。听起来有点强硬但对拖延症极其有效。团队需要建立一种共识代码审查是项目的一部分不是可以在时间线上无限搁置的负担。4.2 大改动拆不开、历史提交一团乱怎么破总会遇到跑不掉的巨型改动比如一次依赖大升级、一次数据库迁移。这种情况下硬拆 MR 不现实因为改动之间高度耦合。我的处理方法是分阶段推进而不是一次性提交全部内容。第一个阶段是纯结构性提交只改接口签名、引入中间层、更新类型定义不做行为变更。第二个阶段是逐模块替换实现每个模块一个 MR保持其他模块不受影响。第三个阶段是清理删除最后把第一阶段引入的兼容层删掉。整个过程看起来像三个大 MR但每个都能独立审查、独立回滚。至于历史提交混乱的问题经验是勤用 rebase 而不是 merge。开发分支尽量保持一个 MR 一坨改动的朴素状态不要动辄拉出一个 feature 分支就疯狂 merge 主分支。主分支更新了用 rebase 把自己的 commit 挪到最新MR 时间线干净得多。顺便说一个小技巧rebase 前先创建备份分支万一 rebase 过程翻车可以轻松找回。4.3 审查疲劳被 Review 淹没之后的破局办法当团队规模变大或节奏变快reviewer 可能一天要看十几个 MR每看一个都集中注意力这天黑之后基本没精力写自己的代码了。审查疲劳会让质量急剧下降这比没人看还危险——因为有人看了但没看透。我的破局方案是给审查者设上限。规定单个人一天的 MR 审查数量不超过 5 到 6 个每个 MR 需要全神贯注的时间窗口。如果数量超过Maintainer 需要分配更多 reviewer 或推迟非紧急 MR。与其让一个人勉强看 12 个 MR 每项都看走眼不如让 3 个人各看 4 个更可靠。另一招是引入自动化的初筛。lint、静态检查、测试覆盖率这些不需要人来做判断的部分全部交给流水线。只有自动化通过之后才进入人工审查这样人工注意力被浪费的几率和速度都降低不少。还有个容易踩的坑是翻来覆去磨同一小块代码。有时候一个 MR 改了 30 轮其实后面十几轮都是对同一段逻辑的来回修改。碰到这种情况我建议直接拉上作者和审查者开会聊 10 分钟当场敲定最终方案回到电脑前直接改完合入。持续在讨论区里打文字仗成本远高于口头对齐。5. 最后让我把话茬儿落在这里做完这套 open-code-review 机制之后我最明显的体感不是 bug 变少了——虽然确实变少了——而是团队对改代码这件事的认知变了。大家不再把 review 看成被人挑刺而是把它看成一次给代码把关、给队友搭把手的机会。新人在公开的讨论记录里学到的是团队怎么做决策而不是代码改成什么样能过审。如果你正在犹豫要不要在团队里做类似的事情我的建议是别一上来就搞大刀阔斧先从三个小动作开始把 MR 描述模板加上改动原因和验证记录两栏把审查意见按 P0/P1/P2 分级把所有评论必须 resolve 才能合入开起来。这三样落地之后再看团队反应往往审批质量已经改善了一大截。后面再逐步加上分组角色、自动化流水线、新人引导这些进阶玩法。据我所知代码审查这件事永远没有最优解只有持续打磨后的最合适解。你能走的第一步就是让下一次 review 比这次稍微公开一点、稍微认真一点。
返回列表