ARTICLE DETAIL

资讯详情

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

代码审查怎么做?一套开放协作的 Code Review 工程化实践指南

代码审查怎么做?一套开放协作的 Code Review 工程化实践指南 1. 为什么我盯上了 open-code-review 这件事1.1 一次低级的线上事故让我重新思考 code review先讲一个真实经历。几年前我带一个四人小组做交易后台有一次上线前一个改动只有三十来行的合并请求负责的同事在聊天软件里喊了一声“改完了求合并”我看了一眼标题觉得没问题顺手就合了进去。结果上线半小时后线上订单金额批量算错原因是把金额计算从浮点数换成了 BigDecimal但有一处除法没指定舍入模式默认值在一些极端数据下直接抛异常被上层兜底逻辑吞掉后落成了错误金额。问题不在那行代码本身而在它经过的流程。那次之后我做了个硬性要求所有合并必须走代码审查code review。但新问题马上来了。团队很快学会了“形式化遵守”有人秒批有人只看不评有人复制模板话术。我翻过一周的合并记录绝大多数审查意见是“LGTM”“没问题可以合并”真正指出设计缺陷、边界条件问题的评论不到百分之十。这让我意识到光有“必须 review”这条规则不够要让它真正起作用必须设计一套开放、可交互、能积累的机制。我把这套机制整理成了 open-code-review它不是一个具体的开源软件而是一整套代码审查的工程化方法开放流程、开放反馈、开放复盘。今天这篇文章就是想把整套东西掰开揉碎讲清楚。1.2 open-code-review 想解决的三类典型痛点这些年接触过的团队不论规模大小在代码审查上踩的坑基本可以归类成三类。第一类是流程封闭。审查只在发布前临时做代码合并就是终点审查意见没人追溯过程不透明。想复盘一个决策的时候翻遍聊天记录也找不到当初为什么这么选。第二类是流于形式。审查人没有足够的上下文也没有明确的审查清单只能对着 diff 泛泛而看最后给出“代码风格没问题”这类无关痛痒的意见。作者收不到有效反馈慢慢就把 review 当成一个必须忍受的流程关卡。第三类是经验不沉淀。几十条有价值的讨论散落在聊天窗口里没人整理也没人复用。同样的坏味道下一个 PR 里还会再犯一遍同样类型的线上隐患换个场景又冒出来。open-code-review 的思路就是把这三件事分别用流程、工具和习惯来兜住。“open”的含义也分三层流程公开透明每个人都能看到任何一次变更的评审全过程反馈开放平等鼓励新人提问、鼓励跨模块认领审查复盘开放可查所有结论都沉淀到代码仓库里让后人能通过 git 历史和 PR 记录还原当时的决策现场。2. 整体设计思路把审查从“关卡”变成“协作”2.1 先转变审查心态很多团队把 code review 天然理解成“审批”我提交代码你检查你放行然后发布。这种模式下审查者像机场安检作者像乘客双方的目标可以说是对立的——作者想早点走审查者想查细一点。这种对立一旦形成审查质量就不可能高。我后来在团队里反复强调一句话审查者不是审批官是同行评审者。你要做的是帮作者一起把方案想清楚而不是站在关卡上决定放不放行。这个心态转变非常关键。它意味着审查意见要从“这里错了改掉”变成“这个实现方式我有疑问因为一旦遇到 XX 情况可能会出问题或者我们换个方案会不会更好”。配合心态转变我把每个 PR 的评审节奏重新梳理了一遍作者先自审再交给指定伙伴做逻辑审查最后过自动化检查。这三级不是层层审批的关系而是三种不同的视角自审查的是“我是不是把代码写顺了”伙伴审的是“这个改动会不会破坏别的解释”自动化检查兜底的是“有没有明显的低级错误”。2.2 分层审查策略实践中让每个人对每个 PR 都做全量深度审查并不现实。人眼注意力是有限资源团队越大这个矛盾越明显。所以我把审查拆成四层按照风险程度决定到底要打几层。第一层是作者自审。提交合并请求之前至少花 15 分钟把 diff 从头到尾过一遍把明显的调试代码、临时写法、拼写错误先修掉。这个动作成本最低收获最高。第二层是伙伴审查。由熟悉相关模块的一名开发者重点看逻辑正确性、边界条件和测试质量。这是代码审查的核心层也是大多数团队最需要加强的一层。第三层是自动化检查。格式规范、静态缺陷、依赖安全、测试覆盖率等能由机器确定性判断的内容全部交给 CI 把关。第四层是专家抽查。对于涉及支付、权限、对外 API 这类高风险变更由资深开发或架构师做一轮额外的冷眼审查重点放在设计合理性和长期演进上。每层职责清晰责任人明确。这样不会出现“大家都在看但谁都没看细”的情况。2.3 哪些交给脚本哪些必须靠人眼自动化检查不是越全越好关键是看分工。我给团队划定了一条线可确定性判断、重复成本高、规则能够表述清楚的交给脚本需要设计判断、需要理解业务上下文、需要权衡取舍的必须靠人。适合脚本检查的包括代码格式与导包顺序、未使用变量和死代码、命名规范匹配、圈复杂度阈值、简单重复代码、依赖中的已知漏洞版本、没有断言的测试方法等。这些项目给机器做又快又准人反复检查会产生“检查疲劳”反而容易漏掉真正重要的问题。必须人眼判断的包括模块边界是否合理、未来需求扩展时这个设计是否还能撑得住、并发逻辑在实际请求模型下是否真的安全、慢查询在数据量增长后是否还能接受、异常处理路径能否自愈或者正确报错、用户输入有没有在不经意间被拼接到高风险操作里。这些问题没有一个能靠规则穷举它们依赖审查者对系统全貌的理解。打个比方自动化像是安检口的体温检测仪做快速筛查人眼审查像是医生的问诊做精准诊断。你不能指望体温枪查出感冒的病因也不能让医生站在安检口重复量体温。3. 实操落地搭一套能长期运转的开放评审机制3.1 提交粒度控制从源头降低审查成本代码审查最怕遇到大 diff。一个 PR 塞进来八百行甚至上千行审查者看到时就容易产生畏难情绪随便扫几眼就放弃深度。这里有一个在业内反复被验证的规律单个变更超过 400 行时有效评论密度会肉眼可见地下降控制在 200 行左右时审查质量和讨论深度最高。所以控制提交粒度是 open-code-review 落地时最值得投入的一项工作。操作上可以这样拆一个 PR 只解决一个问题或者是一个完整且可以独立发布的小功能如果需求本身很大拆成分支栈或者“先引入新能力再替换旧调用”的两阶段提交。不要怕拆出来的步骤没法单独上线让每一步都能编译、能通过测试、回滚也安全本身就是高水平的重构习惯。举个例子我们团队做过一次把 Float 金额字段统一替换成 BigDecimal 的改造。一开始同事提了一个一千多行的 PR我把这个 PR 退回去让他先提交一个“新增金额工具类并补齐测试”的 PR再提交一个“逐步替换业务调用”的 PR。两个 PR 都控制在 300 行左右审查质量上来了问题也提前暴露了——第一个 PR 里的舍入策略就被发现少考虑了一种业务场景。3.2 用模板把“审什么”变成默认动作写代码的人打开一个空白 PR 页面时往往不知道该写什么描述。审查者面对一个没头没尾的 PR也不知道该从哪里问起。解决这个问题最省力的方式是设计一份强制使用的 PR 描述模板。模板不需要很复杂核心是逼作者把改动背景、影响面、测试验证说清楚。我们用了下面这个模板效果很明显。## 变更目的 说明这次改动解决了什么问题为什么有必要做 ## 变更内容 列出关键改动点重点标注行为变化 ## 测试验证 - [ ] 本地测试已通过 - [ ] 新增/修改了单元测试覆盖以下变化点 - [ ] 边界条件和异常输入已检查 - [ ] 大对象/连接等资源已确认释放 - [ ] 新依赖或配置变更已通知运维 ## 自检清单 - [ ] 没有调试代码/临时代码 - [ ] 没有重复造轮子 - [ ] 日志内容不会泄露敏感数据模板自然带有“必须勾选”的压力作者走完这个过程就已经完成了一半的自审。模板的形式本身不重要关键是让作者在提交前就从审查者的角度对自己做一次提问。3.3 一份可以直接抄的审查清单有了模板还需要一张给审查者用的检查清单。我把它按维度整理成了一张表挂在团队文档里也打印贴在工位上。下面是比较通用的版本。维度重点检查项逻辑与正确性分支条件是否覆盖全边界值和空值是否处理并发场景有没有竞态计算精度和类型转换是否安全安全与权限用户输入有没有被拼接到 SQL、HTML、命令敏感信息有没有打进日志或镜像权限校验是否最小化性能与资源循环里有没有数据库查询或外部调用文件、连接、线程池是否及时释放大集合是否一直被持有不释放可维护性命名是否表达意图新增代码是否与现有模块职责一致有没有引入不必要的重复概念测试质量新逻辑是否有测试断言是否有意义异常路径和边界场景有没有覆盖测试是否真实模拟了使用场景有人问过我测试覆盖率要不要设卡点。我的建议是不搞一刀切。核心计算逻辑、金额转换、权限判断这类高危代码覆盖率必须高脚本类、页面样式类改动硬性要求覆盖率只会催生无意义的测试。重点是核心逻辑有没有有效断言而不是数字到了没有。3.4 怎么写出让人愿意改的评审意见审查意见的表达方式直接决定了作者愿不愿意好好改。我踩过很多坑也总结了一套基本格式。一条好的评审意见包含四个要素指出问题、说明为什么重要、给方向而不是死方案、必要的时候附参考资料。比如负面示范“这个方法太长了重构一下。”正面示范“这个方法承担了计算和渲染两件事后续再加一种结算方式时容易漏改。建议拆成纯函数和渲染两部分测试也会更好写。”第一句话只是结论没有上下文第二句话讲了影响力和理由作者看了就知道问题出在哪、怎么改、改了有什么好处。讨论的时候还要注意优先级分级。我们把评论分成 P0、P1、P2 三级。P0 是不改会出事安全漏洞、金额错误、数据毁坏P1 是强烈建议改可维护性问题、明显性能风险P2 是可选优化。这样作者能快速判断哪些意见必须回应哪些可以后续迭代不会因为满屏评论产生抵触心理。4. 真正跑起来之后团队协作里的暗礁与探测方法4.1 审查积压到无人处理制度刚立起来的时候团队里经常出现一个场景PR 建好了晾在那里两天没人 review。原因主要有三种PR 太大没人敢碰、没有人明确认领审查职责、大家默认“别人会去看”。应对方案是这样的。我们约定 PR 创建后 24 小时内必须至少有一个审查者响应如果没有第二天站会上要把阻塞原因同步出来。同时用仓库的 CodeOwner 机制自动指派 Reviewers让每次变更都有一个默认负责人而不是靠自发的“搭把手”。对于超过 48 小时无人处理的 PR自动进入升级流程由技术负责人介入协调。这套规则看起来生硬但能非常有效地阻止 PR 拖成技术债。还有一个免费的技巧团队里约定“谁最后确认了新需求谁负责推动它落地到合并”。让需求提出者参与推动而不是全部压在写代码的人身上。4.2 评论变成“争吵”民主氛围浓一点的团队容易出现另一种情况评论区的讨论逐渐变成站队和争论一条 PR 下面刷了一百条消息话题从技术方案跑偏到个人偏好最后不了了之。我的处理经验是定两条约定。第一任何争论如果在评论里超过 10 分钟还无法收敛立刻转到线下或者视频会议里画图讨论不在评论区里无限刷屏第二允许作者有选择地接受建议但拒绝时必须给出理由如果双方僵持不下约定由一位不做直接改动的第三方来仲裁。还有一个非常实用的表达约束把“我不同意你的方案”改写成“我没有理解这个方案在遇到 XX 场景时如何应对你能解释一下吗”。前者像是在宣战后者是在求解。很多时候换个提问方式讨论就能从对抗变成合作。4.3 新人面对陌生代码库不敢出声新加入团队的同事面对一堆不熟悉的模块通常不太敢在代码审查里发表意见。这个阶段反而最需要保护他们的参与感。我们试过一种“新手巡逻”机制前两周新人不写自己的大功能专门去看别人提交的 PR只提问、不改代码。很多看起来习以为常的设计在小白视角下反而能暴露出文档缺失和可维护性问题。老同事也受益因为解答问题本身就是一次重述设计逻辑的整理过程。氛围上要刻意避免“这么简单你都不会”之类的反问。哪怕有些问题看起来基础也要当作一次免费文档补全的机会来对待。4.4 历史代码要不要补审团队把新代码审查跑顺之后经常有人问老代码要不要回头补审。我的建议是不要一刀切地补成本太高收益也未必成正比。对风险特别高的模块比如支付、权限、对外开放的 API可以按风险级别挑重点做一次专项代码走查普通业务代码在每次改动到它的时候顺带重构成可审查的样子远比一次性翻锅式地重审有效。渐进式改造才是技术债清偿的正常姿势。5. 常见问题与排查技巧实录5.1 高频问题速查表把实践中遇到的高频问题整理成一张速查表方便对照处理。现象根因解法PR 描述永远是空的没有默认模板启用 PR 模板CI 检查描述必填项为空则禁止合并审查者永远只回“LGTM”没认真看或不敢说要求每条意见给出具体问题坐标定期抽查 review 质量CI 跑得太久每次都在全量跑PR 阶段只跑变更相关的测试合并前再做全量回归自动化检查误报太多规则没有区分存量与新增存量告警进基线清单新代码零新增告警每周清理基线小团队没有架构师兜底没有长期技术视角轮值审查 每月一次 25 分钟集体代码走查作者收到一堆评论不改评论没有优先级评论分 P0/P1/P2作者只需落实 P0 和 P1P2 可延后5.2 我的避坑经验最后分享几个我在真实项目里踩过坑才总结出的心得。不要在 review 时直接改作者的分支。哪怕那个问题很明显也尽量通过评论让作者自己改。表面上这是节约时间实际上下次他还会犯同样的错误。让写代码的人亲手修掉自己的问题是能力建立的关键路径。不要用“每日评审条数”作为团队考核指标。一旦这个指标被创造出来就会出现大量的互吹评论和刻意拆小 PR 刷数量真正有效的讨论反而变少了。要么不统计要统计就统计“线上缺陷中有多少是 review 阶段没拦下来的”后者才是有价值的信号。不要指望 review 能替代测试环境验证。代码审查擅长发现设计问题、逻辑错误和维护性隐患但复杂系统的状态流转还是要在真的环境里跑一遍才能放心。5.3 review 意见的撰写格式值得反复打磨这里多说一句。很多团队的技术氛围不好根源不是人不好而是表达方式太差。我要求团队在 PR 评论里统一用“问题 影响 建议”的格式拒绝只给结论不给原因。举个例子与其写“这里有并发问题”不如写“这里的缓存读取不是原子的如果两个请求同时走到这段逻辑可能出现重复发放优惠券建议用分布式锁或者把操作收敛到单线程队列里”。有因有果作者改起来就知道方向成长也更快。6. 从工具到文化我的最后一些体会要说 open-code-review 这套东西最大的价值我觉得不是减少了几次线上事故而是改变了一个团队看代码的方式。代码不再是某个人的私有领地而是团队共同拥有、共同负责的资产。如果让我给刚起步的团队一个建议我会说先别折腾任何高级工具从今天开始给每一个 PR 配模板、设审查者、定分级意见格式就已经足够让代码审查质量上一个台阶。工具只是放大器流程的设计和团队的心态才是底座。最后分享一个小技巧。我们在每个 PR 上让作者、审查者、CI 三方都留下可见的确认状态谁在看、看到了什么、机器人查了什么全程留痕。时间长了你会发现每个人在提交代码之前都会主动自查得更多因为没人愿意在同事面前反复犯低级错误。这个惯性一旦建立代码审查就从“管理工具”变成了“成长机制”这也是整个流程让我觉得最有价值的地方。
返回列表