首页 / 资讯中心 / 文章详情

open-code-review:用自动化流程让Code Review不再流于形式

open-code-review:用自动化流程让Code Review不再流于形式 ★ FEATURED ARTICLE
1. 整体思路与核心矛盾为什么多数 Code Review 都死在形式上先说说我为什么要折腾 open-code-review 这套东西。过去几年我带过不少研发小组也见过太多团队上一秒刚宣布“从今天开始我们严格执行 Code Review”下一秒 MR 就变成“LGTMLooks Good To Me”刷屏现场。代码质量不是靠一句口号就能解决的Code Review 越做越流于形式通常逃不出三个死结。第一个死结是没有审查清单大家凭感觉看代码。审阅者打开 MR 后不知道重点看什么于是草草扫一遍就点了通过。第二个死结是 MR 设计得太差有人一条分支能攒一千多行改动覆盖五六个功能点审阅者根本看不出这次改动的初衷。第三个死结是审查结果没有闭环今天发现的“求求了别再用全局变量”问题两周后在另一个 MR 里又原样出现大家连回头的机会都没有。所以启动 open-code-review 这个项目时我给自己定的目标不是“把代码审查流程做得更规范”而是“让代码审查成为团队技术债务的早期预警系统”。实现这个目标只靠一套开源工具显然不够我把整个方案拆成了四层编写可执行的审查规范、设计标准化的 MR 模板、用脚本自动统计审查数据、最后通过机器人把结果推送到 IM 工具。这套方案最核心的一条设计原则是用工具约束代替人为自觉。规范写得再漂亮没有工具强制卡住入口最后都会沦为纸面文章。比如 MR 描述必须填测试影响范围、单次 MR 超过 300 行就自动打上“大改动”标签这些都不靠人工提醒而是从 CI 阶段就拦截处理。另外一个容易被忽略的初衷是这套流程必须“对新人友好”。团队里有刚入职一两周的毕业生也有写代码多年的老油条。我拿 open-code-review 去适配不同水平的成员时发现只要规则足够具体、反馈足够及时新人反而上手最快。相反老员工往往习惯“我改了就是改了你别拦我”的节奏这个矛盾等到后文踩坑部分再展开讲。1.1 为什么不用现成的代码质量平台这里必须做一个选型说明。市面上的开源代码扫描工具很多但 open-code-review 的定位不是“静态扫描器”而是“流程治理工具”。静态扫描器解决的是“这段代码有没有 bug、有没有明显反模式”而代码审查流程要解决的是“这次改动到底解没解决问题、影响面有多大、下一次出问题时能不能快速定位”。两者完全不同。我见过团队把 SonarQube 之类的工具接入仓库后就以为万事大吉结果扫描报告越攒越多真正去看的人寥寥无几。原因很简单——扫描结果没有和 MR 决策流程绑定它只是一份“参考报告”而不是一个“检查关卡”。open-code-review 做的恰好是把这些关卡串联起来。CI 阶段输出静态扫描结果和代码行数统计数据脚本根据 MR 的标题、描述和改动规模生成一个“审查评分”再把这个评分作为合并请求的前置条件。评分不及格的 MR要么补写描述要么拆分提交要么拉上对应负责人解释原因。这套逻辑用现成平台反而做不到那么顺手与其被平台功能绑架不如自己写个几百行的脚本更可控。1.2 方案全景open-code-review 到底包含哪些组件先给你看一张全景图这里不用图表工具直接列出来。整个 open-code-review 体系由五个部件组成MR 模板统一提交描述结构让审阅者能在 30 秒内搞清楚改动背景代码统计脚本基于 cloc 统计每次 MR 的改动行数、文件数识别超大改动评审评分卡基于 Python 脚本解析 MR 信息生成 0100 分的评审得分规则机器人通知把评审结论自动推送到飞书/钉钉/邮件提醒相关责任人双周报告周期性汇总审查数据量化团队代码健康度趋势这套组件最初就我一个人写前后大概花了一个多月才稳定下来。核心代码加在一起不到 1500 行全部开源放在仓库里后续团队可以直接拉下来改配置使用。这也是项目名叫 open-code-review 的原因——它不是一个封闭的内部平台而是一套可以自由剪裁的开放方案。2. 流程规则设计与 MR 规范30 秒内看懂一次改动的艺术流程设计的核心是把“代码审查”这种看起来主观的行为尽量拆解成客观、可执行、可衡量的步骤。我在 open-code-review 里定义了三套规则提交前规则、审查中规则、合并后规则。三套规则层层递进分别对应 MR 创建阶段、讨论阶段和收尾阶段。提交前规则管的是“开发者必须做什么”。最基础的一条是 MR 拆分——一个 MR 对应一个明确的功能点或缺陷修复严禁混入无关改动。如果发现某个 MR 里同时改了用户注册逻辑和订单导出格式审阅者可以直接打回。第二条是描述质量要求必须写清楚“改了什么、为什么改、影响范围、如何验证”这四条少于两条就算不合格。审查中规则管的是“审阅者应该看什么”。我给团队设计了一张非常具体的审查清单不是那种空泛的“注意代码质量”而是列出十个检查点功能逻辑是否正确、边界条件是否处理、安全性有没有隐患、兼容性是否考虑老版本、性能上有没有明显浪费、命名和结构是否清晰、错误处理是否到位、日志是否有助于后续排查、测试覆盖是否包含关键路径、文档和注释是否同步更新。合并后规则管的是“审查结果怎么沉淀”。每次 MR 关闭前审阅者必须打标签approve通过、needs-fix需修改、needs-discussion需讨论。这些标签会进入统计系统作为后续双周报告的数据来源。2.1 MR 描述模板确认背景优先于确认代码大多数开发者的通病是写完代码恨不得马上提交描述就写“fix bug”“update code”这种废话。open-code-review 的 MR 模板在入口就堵住了这个问题。我在 .gitlab/merge_request_templates/default.md 里维护了一份模板## 背景 这个改动解决什么问题不做的代价是什么 ## 改动说明 核心变更点是什么涉及哪些模块 ## 影响范围 可能影响哪些功能是否涉及数据库变更/接口协议调整 ## 验证方式 本地如何验证单测覆盖了哪些场景是否跑过冒烟测试 ## 测试清单 - [ ] 单元测试通过 - [ ] 接口自测通过 - [ ] 影响面回归通过这份模板看起来简单实际运行起来有个很神奇的效果开发者填完背景和影响范围之后自己会发现有些改动逻辑上还说不通。我遇到过两次提交者写完描述后主动去找产品经理对需求改完才发 MR。这说明描述模板不只是给审阅者看的更是逼着提交者把思路理清楚。审查者在 open-code-review 的评分卡里也会对描述质量打出专项分数。只有标题没有描述、或者描述含糊的 MR评分卡直接扣掉 30 分。这样设置的目的是让“写清楚描述”成为一种必要劳动而不是可选美德。2.2 审查时效T1 响应和超时升级机制代码审查最怕拖。一个 MR 挂在 review 列表里两三天没人碰开发者的心态就会从“期待反馈”变成“爱谁谁吧”后面的流程全是形式。open-code-review 里我定了一条硬性规则审查响应时间不超过 1 个工作日也就是 T1 机制。具体操作是MR 发起后机器人会 对应的 code owner代码责任人。如果 4 小时内没人响应机器人会再次 提醒如果超过 24 小时仍无响应机器人会把消息推送到技术组长那里由组长协调安排。听起来有点不通人情但实测下来非常有效。没有人喜欢天天被机器人 为了不被点名大家都会尽量当天处理完分派给 review 的 MR。为了让这条规则落地我在后端脚本里加了超时定时器。GitLab 的 API 里可以查到每个 MR 的创建时间和参与者列表脚本每隔半小时跑一次筛选出超时未响应的 MR然后调用飞书开放平台的 webhook 发送提醒消息。这条链路用 Python 实现核心逻辑不到 50 行。2.3 合并条件质量得分低于 60 分不允许合并open-code-review 里最硬核的规则是 MR 合并前必须通过评分卡检查。评分卡会根据四个维度打分描述完整度占 30 分背景、改动、影响、验证四项各占 7 分缺一项扣 7 分改动规模控制占 25 分单次改动行数越少得分越高300 行以上开始扣分1000 行以上直接 0 分静态检查情况占 25 分[静态扫描工具] 检查结果中没有任何 error 级别问题得满分有 warning 每项扣 2 分审查轨迹完整度占 20 分至少一个非提交者 approve、回复数不少于 1 条、解决了所有讨论才能得满分总得分低于 60 分的 MR在 GitLab 里会通过 Merge Request Approval Rules 设置一个“评分通过”验证任务未通过不允许合并。这条规则的威力只有真的跑起来才知道。第一周团队 23 个 MR 中有 7 个被拦截其中 4 个是因为描述不完整3 个是因为改动规模超出阈值。两周之后被拦截数量降到了 2 个大家都开始习惯性地写好描述、拆小改动。这里要多说一句给评分卡设门槛不是要卡任务进度而是帮团队淘汰那些“低信息量变更”。一次改动如果连描述都写不清楚说明问题识别就不清楚合并进去之后迟早会变成事故。与其让错误代码进入主干不如让改动在 MR 阶段多飞一会儿。3. 工具链实现从 CI 脚本到机器人通知的完整落地规则说完了下面是硬核部分。我尽量把 open-code-review 里用到的技术栈、脚本结构和配置方法一次讲清楚方便你直接抄作业。技术栈选型上我没有引入任何重量级服务。仓库托管用的 GitLabCI 用的 GitLab CI代码统计用的 cloc后端逻辑用 Python 3 写通知走的飞书 webhook。选这套组合的原因有两个一是团队对 GitLab 和 Python 非常熟维护成本低二是这些组件全都支持命令行方式运行在 CI 里跑起来非常干净不需要额外起服务。如果你用的是 GitHub Actions 钉钉或者 Gitee 企业微信原理也是完全一样的。核心思路就是把“读取 MR 信息 → 计算得分 → 推送结果”这条逻辑放到 CI 的一个独立 job 里让它作为合并的前置检查。3.1 CI 配置示例用 cloc 统计改动规模第一步是统计 MR 的改动规模。cloc 是一个用 Perl 写的代码行数统计工具可以根据语言类型统计新增行、删除行、注释行等数据。在 CI 里使用非常方便拉取 MR 分支后直接跑# 在 CI 中安装 cloc apt-get install -y cloc # 统计与主干分支的差异 cloc --diff --by-file origin/master origin/merge-request-source-branch \ --outcloc_output.txt \ --report-filecloc_summary.txt \ --quiet这里要想办法换算成“净新增行数”。我的做法是读取 cloc_summary.txt 里 SUM 那一行的 added removed 之和把它当成 MR 的总改动规模。之所以不只看 added是因为有些 MR 会大量删代码再重新写added 看着不多实际风险不低。取得改动行数后CI 会把两个变量传给后面的 Python 脚本一个是$TOTAL_LINES一个是$CHANGED_FILES。这两个数据会作为评分卡里“改动规模控制”维度的输入。3.2 评分脚本 review_score.py解析 MR 信息并计算得分MR 描述和审查轨迹的数据可以从 GitLab API 拿到。我写了一个 review_score.py 脚本整个执行流程是#!/usr/bin/env python3 # review_score.py - open-code-review 评审评分脚本 import os import json import urllib.request def fetch_mr_info(project_id, mr_iid, token): 从 GitLab API 获取 MR 元信息 url fhttps://your-gitlab.example.com/api/v4/projects/{project_id}/merge_requests/{mr_iid} req urllib.request.Request(url, headers{PRIVATE-TOKEN: token}) with urllib.request.urlopen(req) as resp: return json.loads(resp.read().decode(utf-8)) def score_description(mr): 描述完整度背景/改动/影响/验证 四项各 7 分缺一项扣 7 分 desc mr.get(description) or required_sections [背景, 改动说明, 影响范围, 验证方式] # 注意这里根据 MR 模板结构判断实际开发时用 markdown 标题解析更准 score 30 missing 0 for section in required_sections: if section not in desc: missing 1 score - missing * 7 return max(score, 0)这段代码只是示例生产环境里我会用 python-gitlab 这类 SDK 来代替裸的 urllib 请求处理分页和异常会省心很多。我还把评分规则的参数抽成了一个 config.json方便团队自己调权重{ weight_description: 30, weight_size: 25, weight_static_check: 25, weight_review_trail: 20, size_limit: 300, size_score_full: 100, static_check_error_penalty: 25, static_check_warning_penalty: 2, approve_required: true }一个很关键的设计细节是评分脚本本身不应该有“最终决策权”它只输出得分和建议真正的 HARD BLOCK 交给 GitLab 的 Approval Rules 配置。这样既保留了自动化检查的强度又在特殊情况下留了人工解除限制的口子。3.3 机器人通知把评分结果推进 IM 群评分完成后下一个问题是怎么让得分和拦截信息到达相关人的眼前我写了一个 send_notification.py在 CI job 末尾调用把评分结果拼成卡片消息通过飞书 webhook 推送。消息卡片长这样【MR 评审提醒】#1234 修复订单金额精度溢出 提交者张工 | 项目order-service 改动规模新增 128 行删除 23 行共修改 7 个文件 描述完整度通过 静态检查0 error2 warning 评审评分87 分通过 处理超时提醒待评审已等待 6 小时这个卡片发到群里之后有两个作用一是公开曝光不合规的 MR利用“人人可见”的社交压力推动改进二是提醒对应 code owner 尽快响应。我特意在卡片里带了 MR 链接手机上点击直接跳转到 GitLab 页面省去了一层层翻菜单的功夫。通知脚本里有个小细节我做了“静默模式”如果评分超过 80 分只在群里发一条简短通知不发卡片。如果评分低于 60 分或者超时未响应才会发完整的卡片消息。这样做的目的是避免日常群消息被机器人刷屏否则大家会产生“通知疲劳”真正重要的消息反而没人看了。3.4 代码库结构谁负责维护哪些内容open-code-review 的仓库结构在团队里也被定义得非常清晰大家都知道该改哪里、不该动哪里open-code-review/ ├── README.md # 总览文档说明方案定位和接入方式 ├── config/ │ ├── default.json # 评分卡权重配置 │ └── codeowners.yml # 各模块 code owner 名单 ├── scripts/ │ ├── review_score.py # 核心评分逻辑 │ ├── send_notification.py # 飞书机器人推送 │ ├── weekly_report.py # 双周数据汇总 │ └── check_template.py # 检查 MR 描述是否符合模板要求 ├── .gitlab/ │ └── merge_request_templates/ │ └── default.md # MR 模板 ├── .gitlab-ci.yml # CI 流程定义 └── tests/ ├── test_review_score.py └── test_parse_mr.pycodeowners.yml这个文件非常有用。它记录了每个模块的负责人MR 创建后机器人会自动 对应负责人来 review避免“大家都在群里却没人觉得自己该看”的尴尬。我见过不少团队把 code review 当成全团队的公共责任结果就是无主之地谁都不管。指定 owner 之后责任边界一下子就清楚了。4. 排障与优化open-code-review 落地过程中踩过的坑工具写了三个月真正在团队里稳定运行花了快半年。中间踩过的坑我整理成几个典型问题按“症状 → 排查 → 解法”的格式列在下面希望你能少走点弯路。4.1 问题一reviewer 一直不响应机器人提醒也无效症状MR 挂了两天机器人 了 code owner 三次对方就是不点开看。排查一开始我以为是把PRIVATE-TOKEN配错了后来查看日志发现提醒消息已经推送成功问题出在“消息发出去了但没进到对方看得见的地方”。因为飞书 webhook 发到的是公开群如果对方把群聊折叠了根本看不到。解法我给通知脚本加了“个人提醒”逻辑。每次 MR 超过 6 小时无人响应时除了群里发卡片还会调用飞书 API 直接给 code owner 发一条私聊消息。如果超过 24 小时消息会同时抄送给技术组长。加了这层之后60% 的未响应问题在当天就被解决了剩下的 40% 属于 code owner 出差或休假的特殊情况升级给组长处理是合理的。这里还有一个隐性坑就是 codeowner 配置必须维护正确。团队有成员离职时记得把 codeowners.yml 里的名字同步更新否则机器人会一直往一个没人看的账号里发私信等于空转。4.2 问题二超大 MR 的历史债怎么补症状项目里有几个存在了很久的功能分支动辄一两千行改动按 open-code-review 的评分规则永远过不了门槛但业务又确实需要它合并。排查我一开始也头疼总不能因为一个 MR 太大就一直卡在僵局里。后来发现这根本不是技术问题而是流程问题——当初把这堆改动搅在一起做的人就没有想过怎么拆。解法针对这种“存量老分支”我开了一个特殊通道允许在 MR 描述里标记“historical-merge”历史债务合并但附带两个附加条件。第一必须列出所有无法按时完成的子任务清单第二合并后一周内必须提交技术债务迁移计划。这样的好处是既不拿死规则卡正常业务又把这笔债正式记到技术账本上而不是假装看不见。这种事多来几次之后团队慢慢形成共识拆分支越早越好攒一个大 MR 到最后反而更痛苦。从数据上看新 MR 的平均改动行数从最初的 460 行降到了第三个月的 210 行基本符合预期。4.3 问题三评分卡变成“应试答题”大家开始刷分数症状有几位同事发现描述中只要包含“背景”“改动说明”“影响范围”“验证方式”这些关键词就能拿高分于是开始写套话比如“背景无”“影响范围无”。表面上评分卡的描述完整度得了满分实际上 MR 的信息量依然是零。排查这是我见过最典型的数据治理问题——指标一旦被公开展示就会有人去钻空子而不是去改善真实质量。单纯加大惩罚力度也不行反而会助长更隐蔽的造假。解法我把描述评分从“关键词匹配”改成了“信息熵判断”。具体做法是统计描述文本去重后的有效字符数低于 100 字符直接 0 分同时如果描述里出现“无”“N/A”“同上”这类模板化词缀额外扣分。更狠的一步是把描述质量分改成“审阅者满意度”和“文本特征分”的加权平均但这部分需要人工打分团队规模小的时候还能撑住人多了就不太够用了。我给后面想接入 open-code-review 的团队一个建议不要在评分规则上耗费太多精力规则过了 80 分那条线就收手把剩下的精力放在更重要的流程设计上。评分卡只是辅助不是目的。4.4 问题四机器人刷屏导致通知疲劳症状扫描和通知脚本上线后群里每天有二十多条机器人消息大家直接把群折叠了。排查我复盘了一下发现问题出在“每条 MR 都推卡片”的粗暴逻辑上。大多数 MR 是正常合规的正常的东西反复提醒只会让人麻木。解法把通知策略改成“三级通知”。第一级是 MR 创建后仅在对应 code owner 的私聊里提醒。第二级是评分通过时只在每周汇总报告里出现不单独发消息。第三级是评分不通过或有高危标签时才在公开群里发完整卡片。这样公开群里的消息量从每天二十多条降到了三到四条而且每一条都是真正需要人关注的。如果你打算复刻这套方案我强烈建议把“减少干扰”当成和“提升覆盖率”同等重要的目标来设计。通知系统做得好是让必要的人看到必要的信息做得不好就是把所有信息发给所有人最后等于没发。4.5 问题五为什么最后没有把“合并门槛”放到 80 分我把评分卡设计成 60 分作为 HARD BLOCK而不是更高的阈值这个决策背后也是踩过坑的。一开始我设的是 85 分结果第一周有 12 个 MR 被拦截业务抱怨流程太慢直接导致两个本应上线的需求延期。后来反思发现评分卡不应变成过度设计的卡流程工具它只需要拦截最不合规的 20% 就够了。60 分这条线刚好卡在“明显不合格”和“可以改进”的中间。低于 60 分的 MR 往往同时存在描述缺失、改动过大、没有审查记录等多个问题60 到 80 分的 MR 会有一些问题但总体可控合并后由开发者在下一轮迭代里自行优化。事实证明门槛设得太高会产生逆向激励——大家宁可不发 MR 也不愿意改代码那后果比流程宽松严重得多。5. 双周报告与分析用数据让团队看见代码健康度变化流程一旦稳定运行接下来最重要的事就是建立反馈循环。open-code-review 包含一个双周报告脚本 weekly_report.py它会在每两周的周日晚间读取 GitLab 上的 MR 数据聚合生成一份 Markdown 格式的团队代码健康度报告然后发送到飞书文档。报告核心指标有五个MR 总数与平均改动行数反映提交粒度是否合理审查响应时长中位数反映 review 是否及时审查不通过率首次提交被打回的比例反映提交质量每个开发者的平均评分用于定位个体问题但不公开排名前十项高频问题标签映射到重复出现的技术债务这份报告最大的价值不是给管理者看的“团队很努力”的 PPT 素材而是给每个开发者看自己的变化趋势。我把个性化部分单独拆出来私聊发给每个人而不是在公开群里展示。比如某个同学这半个月的 MR 平均改动行数比上个月多了 40%系统会提示他“拆分粒度变大了记得保持小步提交”某个同学连续三周出现“缺少日志”的标签系统会建议他去看看同部门老周的 MR 是怎么处理日志的。做到这一步open-code-review 才算真正从流程工具变成了团队习惯的一部分。数据本身不会改变人但是当每个人都能看到自己的数据趋势并且他人做得好的地方可以被直接借鉴时改变就变得自然了。根据团队这半年的运行数据MR 平均响应时间从 26 小时降到了 8 小时评审得分从 60 分出头升到 78 分左右最直观的变化是主干分支上因为低级错误触发的回滚减少了大约一半。双周报告还引申出一个好玩的用法入职新人培训。新同学入职第三周我让他直接把自己的 MR 截图和评分卡调出来对照整个流程走一遍基本就能理解团队对代码质量的期望。比起让他读十几页的研发规范文档这种“用工具学规范”的方式效率高得多。如果你团队人少跑不起双周报告也没关系直接看每个 MR 的评分卡就够了。但一旦超过 15 人我还是建议把周期报告加上因为它能帮你发现那些“单看一个 MR 看不出问题”的系统性趋势。比如某个模块连续四周的审查不通过率持续上升说明它的设计复杂度已经超出团队平均能力是时候考虑重构了。6. 复盘一下这套东西到底在什么团队最划算open-code-review 这套方案并不是银弹我也在不断调整中明白了它的适用边界。如果你带的团队只有两三个人所有代码都写在同一个仓库里那这套方案是为你们添麻烦——两三个人相互已经很熟了你一句我一句聊完就够没必要搞流程和机器人。但当团队规模到了 10 人以上或者有远程办公、跨时区协作的情况代码审查就变成了一件“低信任度”的任务。MR 挂在列表里没人看或者看了也不知道该反馈些什么这种时候 open-code-review 的价值就非常直观地体现出来了。它做的事情是把原本依赖“大家自觉”的环节变成系统自动盯着的关卡。我唯一特别想提醒的是不要在这个过程中忘了“人”的因素。评分卡、CI 拦截、机器人提醒都是手段真正能让代码质量提升的是每个开发者都愿意为别人的代码思考一下、为自己的代码负责一点。我在设计所有规则时都留了人工绕行的口子——不是为了让规则失效而是为了告诉大家系统负责提醒人负责判断。最后分享一个小技巧。如果你准备在团队里推行这套流程别一上来就全量开放所有拦截规则。先用两周时间“只记录不拦截”让大家熟悉 MR 模板和评分卡也让你自己有机会调试规则合理性。两周后再正式打开 HARD BLOCK你会发现团队抵触情绪小很多因为大家已经知道这套工具只是在帮他们变得更好而不是在给谁找麻烦。根据我自己的经验这个过渡期省下来的是后面至少一个月的解释成本非常划算。
阅读完成 · 觉得有帮助?
咨询建站