做代码评审工具这个想法,最初来自一次让我非常窝火的线上事故:一个看起来人畜无害的 PR,把生产环境的配置项从整数改成了字符串,所有机器人的签名校验全挂了。那行代码在评审讨论区里躺了整整两天,没人注意,因为大家根本不会去逐行核对配置文件的类型变化。那次事故之后我开始认真琢磨:代码评审到底应该怎么自动化,才能拦住这种"看得到但看不见"的问题。后来我花了大概两个月的业余时间,把想法落地成一个开源工具,名字就叫open-code-review。
这篇文章不打算写那种"如何安装、如何使用"的说明书,而是把它当作一次完整的项目复盘来写,聊聊我做这个工具时解决的核心问题、踩进去的坑,以及开源之后从真实反馈里学到的东西。无论你是团队负责人、DevOps 工程师还是对代码评审流程不满意的开发者,只要你想知道"一个自动化的代码评审工具到底能干什么、适合干什么、干不了什么",这篇文章应该能给你一些参考。
1. 代码评审的痛点,和我为什么动手写 open-code-review
代码评审这个环节,在所有研发流程里都算得上"人人都知道重要,但没人愿意认真对待"。大部分团队的做法是 Pull Request(或 Merge Request)开起来,指派两个 reviewer,然后就没有然后了。reviewer 要么秒点 Approve,要么在讨论区留下一句"LGTM",真正逐行看代码的人寥寥无几。这不能完全怪开发者懒——大型项目的 diff 动辄几百上千行,人的注意力天然无法长期保持在这种细颗粒度的检查上。
1.1 一次让我下决心自研工具的经历
回到开头提的那次事故。事故定级之后,团队成员复盘时的第一反应是"要在评审规范里加一条:改配置必须单独开 PR"。这个规范听起来有道理,但我很清楚,过不了一个月它就会被遗忘,因为纯靠人记住的规范等于没有规范。
我当时先尝试了几个现成方案。SonarQube 做了静态扫描,也能拦住一部分问题,但它的规则配置非常重,而且对仓库级别的"结构性变更"(比如某个模块整体迁移、某个配置项的类型变化)基本无能为力。GitHub 自带的 code review 功能则完全没有自动化能力,它只是把讨论搬到网上,本质上和线下开会没什么区别。我甚至试过用 GitHub Actions 里的现成机器人,比如 danger,它能基于 diff 做一些评论,但配置复杂度高,规则表达能力也不够直观。
我当时的想法很朴素:既然没有工具能完全满足我的需求,那我干脆自己写一个。这个工具不需要替代人去做评审,它只需要做一件事——把人在评审时最容易忽视、但规则可以明确描述的问题,用自动化手段先筛掉,把人的精力留给真正需要判断力的事情。
1.2 现有工具的取舍:GitHub PR 讨论区、Gerrit、SonarQube 都差在哪
这里有个很重要的判断:为什么不自建一个完整的 Code Review 平台?Gerrit、Phabricator 这些方案其实已经存在很多年了,功能也很成熟。我的看法是,它们的定位偏向"重流程平台",强调的是代码的提交、合并、审核流程可控,适合那种对代码准入有严格要求的团队。但对绝大多数中小团队来说,引入一套独立的评审平台,意味着开发者要在一个新的系统里操作,学习成本很高,和 GitHub/GitLab 的既有 PR 流程又是割裂的。
所以我给 open-code-review 定的核心设计原则是:它是一个接入现有工作流的工具,而不是一个替代现有工作流的平台。它通过 CLI 或者 CI 插件的方式跑起来,读取仓库的 diff 和文件内容,按照规则输出评审意见,把结果以评论的形式发回 PR 讨论区,或者以报告的形式呈现在 CI 输出里。这样团队没有任何迁移成本,只是在现有流程里多了一个"自动 reviewer"。
1.3 项目的整体目标
综合下来,open-code-review 的目标可以拆成四条:
- 自动拦截:把代码中最容易通过规则表达的常见问题(如密钥硬编码、禁止使用的方法、过大的函数、盲目的 catch 等)自动识别出来,在人工评审之前先给出提示。
- 流程接地气:不搞新平台、不搞新账号体系,直接嵌入 GitHub、GitLab 的评论和 CI 流程。
- 规则可编程:让团队可以针对自己的项目写规则,就像写测试用例一样简单,而不是学一套复杂的 DSL。
- 可解释:每条自动评论都带着规则名、触发原因、对应的代码片段,让人觉得它是一个靠谱的助手,而不是一个黑盒检查器。
后面所有实现细节,都是围绕这四条目标展开的。
2. 核心架构与数据模型:从单文件脚本到可扩展工具
工具刚诞生的时候,其实就是一个大概 400 行的 Python 脚本:拉取 PR 元数据、解析 diff、跑几个正则表达式、往 GitHub API 发评论。这个原型跑通了,也确实拦住了几个明显的问题,但当我想把它推广到团队内部、让不同仓库都用起来的时候,单文件脚本立刻撑不住了——每个仓库的规则不一样,有的团队用 Go 写服务,有的是前端 React,规则文件本身必须做成外置的、可配置的,脚本里硬编码的正则显然不行。
2.1 三个核心模块:扫描、评审、规则
重构之后,我把工具拆成了三个逻辑上完全独立的模块。
扫描模块负责从 Git 仓库拿到"当前要评审的内容"。它不直接调用 GitHub 的 PR API 拿到文件列表,而是直接用git diff命令在本地仓库上计算 diff,然后关联到远程分支信息。这样设计有一个很实际的好处:同一套扫描逻辑可以同时服务于 GitHub PR、GitLab MR 和本地分支对比,不需要针对每个平台写一套接口适配。
# 核心操作之一:计算两个分支之间的 diff git diff origin/main...HEAD --name-status git diff origin/main...HEAD --unified=5扫描模块输出的统一数据结构是一个ChangeSet,里面包含所有变更的路径、变更类型(新增/修改/删除/重命名)以及增量内容。后续所有模块都只依赖这个ChangeSet,而不关心它到底来自哪个平台。
评审模块是工具的大脑。它把ChangeSet和规则引擎跑出来的结果合并,决定哪些问题要展示、按什么优先级排序、以什么粒度输出。比如有些规则只关心"新增的代码"而不关心"删掉的代码",评审模块就要把 diff 里的新增行和删除行分别提取出来,传给不同的规则。
规则模块则是我花时间最多的地方。规则用一个独立的配置文件描述,每个规则由几个部分组成:匹配哪些文件(支持 glob 路径匹配)、在什么条件下触发(支持针对 diff 增量的正则或简单的 AST 查询)、触发后给出什么级别的提示(error/warning/info)。
2.2 数据模型的演进:从 JSON 文件到 SQLite
早期的规则配置我用的是 JSON。写起来非常简单:
{ "rules": [ { "name": "no-console-log", "match": "src/**/*.js", "regex": "console\\.log", "level": "warning" } ] }但用了一个月之后,JSON 的弊端就慢慢暴露了:不支持注释,团队加规则时想写一句"为什么这条规则存在"都没地方写;语法太严格,多一个逗号整个配置就崩了。后来我把配置格式换成YAML,加上了description字段,可读性立刻好了很多。
评审结果的存储也经历了类似变化。最开始评审结果只以评论形式发到 GitHub 上,没有本地存储,这就导致一个问题:当你想统计"过去一个月这个仓库被工具拦住了哪些问题"时,只能去翻 GitHub 的 issue 和评论,非常痛苦。后来我加了一层持久化,默认用 SQLite 存评审记录,每一条记录包括仓库名、PR 号、规则名、级别、文件路径和行号。这样不仅能查询历史问题,还能做简单的趋势分析,比如"最近几周硬编码密钥的问题是不是变多了"。
2.3 规则配置的实际形态
抛一个简化的规则配置例子,让大家直观感受一下这个工具的使用方式。它的设计原则是"能直接写正则就不搞 AST,能看路径就不解析语法"。
rules: - name: no-external-secrets description: 在代码中检测疑似密钥字符串,防止硬编码密钥 match: - "**/*.{js,ts,py,go,java}" patterns: - regex: "(?i)(api[_-]?key|secret|token)\\s*[=:]\\s*['\"][A-Za-z0-9+/]{16,}" level: error exempt: - "**/*_test.*" - "**/mock/**"这个规则做的的事情很简单:在所有主流语言的源码文件里,搜索形如api_key = "..."或secret : "..."的字符串,如果冒号后面的内容长度超过 16 位,基本可以断定是硬编码的密钥,报 error 级别的错误。测试文件和 mock 目录自动豁免,因为那里可能故意放了假密钥。
规则引擎的执行顺序也值得一提:先把所有规则按匹配路径进行预过滤,命中文件少的规则优先执行,这样可以提前结束大部分文件的检查,减少无谓的正则匹配。
3. diff 解析这个看似简单实则阴险的环节
很多人写代码评审工具,第一直觉是"直接拿 GitHub 的 API,它会给我 structured diff,按行号标注增删就行"。但我实际做下来发现,diff 解析是整个工具中最容易出 bug、也最影响评审准确率的部分。Git 的 diff 输出虽然看起来简单,实际上隐藏着非常多的边界情况。
3.1 标准 diff 格式里的那些坑
首先是文件重命名。在 GitHub 网页上,一个文件重命名通常显示为R100甚至带相似度,但底层git diff输出的可能是一整段rename from ... rename to ...。如果评审工具只是按普通 diff 解析,很容易把重命名当成"删了一个文件,新增了另一个文件",导致规则误报。比如用户在重命名文件的同时微调了某个 JSON 的字段名,工具应该只关心那几行改动,而不是把整个文件重新扫一遍。
其次是二进制文件。git diff默认对二进制文件不输出内容,而是显示Binary files differ。如果工具不通处理这种情况,强制读内容去匹配规则,整个进程可能会挂掉,或者卡在内存溢出上。我的处理方式是:优先看--numstat输出,如果某一行显示-\t-\tpath,说明这是一个二进制文件,直接跳过内容检查。
第三是chunk 边界。diff 里的@@ -l,s +l,s @@头给出了每个 hunk 的起止行号,但很多人容易忽略一个细节:默认 context 行数是 3 行,也就是说 hunk 里不仅仅包含变更行,还包括变更前后各 3 行上下文。如果一个工具直接把 hunk 里的所有行都当作"变更行"去匹配规则,会产生大量误报。正确做法是区分+、-和空格开头的行,只有+开头的是新增行,-开头的是删除行,空格开头的是上下文。
我在这个环节踩过一个大坑:GitHub 的 diff API 返回的行号是基于 PR 合并到 base 分支后的最终文件行号,而本地git diff返回的行号是基于新分支的头。两者在计算"应当把评论留在哪一行"时结果不一致。最终我被迫统一用本地 diff 作为事实来源,再通过 Git 的git blame或文件内容的行映射来对齐行号。
3.2 处理大 diff 的策略
另一个常见场景是大规模重构产生的超长 diff。有一次我在一个前端仓库上测试,PR 把公共组件从 class 组件改成了 hooks 组件,涉及 120 多个文件、1 万行以上的变动。如果扫描模块把整个 diff 一次性读进内存,解析成对象,内存占用会非常夸张。
我当时的优化策略很简单:把 ChangeSet 里的文件列表先按大小和类型排序,对每个文件单独跑规则,而不是一次处理完整 diff;同时把 diff 解析做成流式的,逐行处理,只保留需要的信息。此外,对大体积文件(比如超过 2MB 的 lockfile、vendor 文件)直接跳过内容检查,只做路径级别的检查,比如"是否存在新增的依赖"这种基于文件名的规则。大幅提升了工具在大仓库上的表现。
3.3 解析器测试:不测真的会翻车
diff 解析器的测试,我一开始完全没做,觉得"不就是字符串处理嘛"。直到有一次在生产环境遇到一个文件的 diff 里包含 Windows 换行符(\r\n),而我在按\n切分行时把\r留在了行尾,导致所有规则都匹配不上。这个吞掉了我一个下午才定位到的 bug,之后我专门建了一个测试目录,里面放各种奇葩 diff 用例:
- 包含中文文件名和路径的 diff
- 空文件的新增与删除
- 只有一个 hunk 但 context 很大的 diff
- 文件内容本身包含
@@ ... @@的 markdown - 删除整个目录时产生的 diff(路径以
/dev/null结尾)
这组测试用例后来开源之后帮到了不少人,GitHub 上有人提 issue 说他也遇到类似的 Windows 换行问题,看到测试用例才发现自己的代码里也有同样的隐患。
4. 规则引擎:从正则匹配到语义分析的硬骨头
规则引擎是 open-code-review 里最有意思、也最容易被低估的部分。它的难点不在于"怎么匹配字符串",而在于"怎么让规则既能表达复杂语义,又不会把使用门槛抬得过高"。
4.1 规则表达能力的边界
做规则引擎的时候,我一度纠结要不要直接引入真实的 AST 解析器。想让工具能识别"这个函数有多长""这个函数是否吞掉了异常""这个 import 是否没有被使用"这类问题,纯正则几乎是做不到的,必须对代码做语法分析。
但问题在于,一个语言一个 AST 解析器,要支持 Go、TypeScript、Python、Java、Rust……工作量是爆炸性的。如果只做几个主流语言,又不太好意思叫"open-code-review"。折中的方案是:规则引擎支持两种模式——轻量级表达式和AST 查询。
轻量级表达式就是前面看到的正则模式,适合快速匹配、跨语言使用。AST 查询则借助一些成熟的开源解析库(不同语言用不同后端),用户可以写类似"匹配所有函数定义节点,长度超过 100 行"的规则。AST 模式的能力更强,但配置更复杂,目前我只对 JavaScript/TypeScript 和 Python 提供了比较好的开箱即用支持,其他语言鼓励社区贡献解析器后端。
4.2 性能优化:多仓库跑一轮不能超过 1 分钟
规则引擎的性能,直接决定了工具能不能融入 CI 流程。如果一个 PR 的评审要跑 5 分钟,开发者早就等得不耐烦了。我定的目标是:一个中等规模仓库(1000 个文件、100 个文件变更)的评审时间控制在 30 秒以内。
具体做了几件事:
- 规则预编译:所有正则规则在加载阶段统一编译成 regex 对象,避免每条规则每次执行都重新编译。
- 文件预过滤:先用 glob 路径匹配把不相关的文件快速过滤掉,只有路径命中的文件才进入正则匹配阶段。
- 多线程执行:Go 的 goroutine 天然适合这种"每个文件独立跑规则"的场景,文件级别的检查并行执行,速度提升非常明显。
- 结果去重:同一个问题可能在正则和 AST 模式下各报一次,引擎要把重复结果合并,只保留级别更高的一条。
一个真实的性能数据:GitHub 上一个用 Go 写的微服务仓库,PR 改动 35 个文件,跑完 142 条规则平均耗时约 11 秒。我觉得这个成绩是可以接受的。如果未来某个仓库规则特别多、文件特别大,需要考虑给规则集做缓存,比如根据文件的 hash 值跳过未变更文件的检查。
4.3 误报控制:这是我被喷得最惨的地方
规则引擎做得再多,如果误报多,开发者不到一周就会在讨论区骂"这破工具又乱报",然后手动忽略它。误报控制直接影响工具的可信度,我在这个上面栽过好几个跟头。
最典型的案例是"检测 console.log"这条规则。它本意是防止前端把调试日志漏到生产环境,但实际跑起来,测试代码、示例代码、文档片段里全在报。后来我给规则引擎加了一种exempt(豁免)机制,规则可以声明自己的豁免路径;同时在规则表达式上支持上下文限制,比如"只匹配函数体内的代码,不匹配函数声明"。这个改动让误报率直接从 40% 降到了 8% 左右。
还有一个更隐蔽的误报来源:正则的贪婪匹配。想象有人写了一条规则,想匹配"疑似包含密码的赋值语句",正则写了password\s*=\s*.+,这条正则在遇到password = getPasswordFromVault()时会误报,因为.可以匹配任意字符。后来我要求规则编写者在规则配置里显式声明"数据流动方向":是从字面量赋值,还是从外部函数返回值。这个细节虽然增加了配置的复杂度,但显著提升了规则的准确性。
5. 与 GitHub/GitLab CI 的集成:从跑通到不烦人
工具做得再好,如果不能自然地嵌入现有开发流程,就不会有人用。open-code-review 的定位是 CLI 工具,核心是通过两条路径接入工作流:一是作为 CI 插件在 PR 里自动跑,二是作为本地 CLI 让开发者在 push 之前自己跑。我实际用得最多的是前者。
5.1 GitHub Actions 的实际接入配置
为了方便团队使用,我写了一个官方 GitHub Action,用法非常简单:
name: open-code-review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run open-code-review uses: your-org/open-code-review@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} config_path: .github/open-code-review.yml level: error这里有个非常容易踩的坑:必须设置fetch-depth: 0。GitHub Actions 默认checkout只拉取当前分支的最新一次提交,没有完整的 Git 历史。open-code-review 要计算 base 分支和 head 分支之间的完整 diff,如果没有历史记录,git diff 命令会直接失败或者只返回极小的一截。这个问题的报错信息还很误导人,看起来像权限问题,实际上是 Git 仓库不完整。
GitLab CI 的配置类似,唯一需要特别处理的是私有化部署的 GitLab。很多公司的 GitLab 是内网环境,GitHub Actions 和 GitLab.com 的公共 runner 都跑不了,要么自建 runner,要么把工具部署在内网的调度器上。我在文档里专门写了 GitLab CI 的配置示例,并且在工具里支持环境变量CI_PROJECT_PATH、CI_MERGE_REQUEST_IID来识别仓库和 MR 号,方便自建 runner 场景。
5.2 评论机器人的设计:不要让你的工具烦人
自动评论这个功能很容易做过头。一开始我的实现是发现问题就发一条评论,一个 300 行的 PR 可能收到 30 条评论,直接把讨论区灌满。后来我从真实使用反馈中总结了三条规定:
- 同一文件的同一规则只报一次,不重复刷屏。
- 用
review级别的评论汇总所有问题,而不是用issue(GitHub 的 issue 评论会触发邮件提醒,太打扰)。 - 支持静默模式:小问题(warning 级别)只在 CI 日志里展示,不主动在 GitHub 上评论;error 级别才在讨论区出现。
这样改完之后,开发者不再觉得工具在"烦人",反而会主动在 PR 描述里写"帮我本地跑一下 open-code-review"。
5.3 支持 stub diff 模式:用本地工具试跑
为了让开发者能push 之前自己检查,CLI 增加了一个stub命令,可以生成一个假 PR diff 在本地试跑。这可以说是本地开发体验里最实用的功能。它的实现也比较简单:CLI 读取本地两个分支的 diff 后,构造一个虚拟的 PR 上下文,跑完规则后把结果以纯文本形式打印,而不需要真的去请求 GitHub API。
# 本地快速验证:对比本地分支和远端 main 的差异,输出评审结果 open-code-review review --base origin/main --head HEAD --local这个模式做出来之后,我在团队里推广的效率高了很多。以前开发者都是被 CI 的红色叉号提醒"你写坏了",现在可以在提交之前自己检查,心态完全不同。
6. 开源之后才懂的几件事
项目开源之后,最大的变化不是 star 数涨了多少,而是我开始收到陌生人提的 issue 和 PR,这逼着我把很多"自己用着还行,但别人用不顺手"的地方认真梳理了一遍。
6.1 文档比代码重要:读文档的人比读源码的人多得多
第一版 README 写得非常随意,只有一段安装说明加两个命令示例,很多用法完全是我心里清楚但没写出来。结果开源第一周,收到的 issue 里有一大半是"这个怎么配置""那个支持吗"。后来我花了整整两天重写文档,加入了Quick Start、规则编写指南、常见问题三个板块。其中规则编写指南是最受欢迎的,因为它把每个配置字段的含义、每个正则示例的匹配目标都讲清楚了,甚至配了解释"为什么这样写更准确"的段落。
我后来才意识到,对一个开源工具来说,使用文档就是产品的第一版界面。代码写得好不好反而没那么明显,文档不好,用户根本走不到代码那个环节。
6.2 从社区反馈中提炼的三个改进
社区反馈最宝贵的部分,是那些我自己从来没遇到过、但别人真实用起来就会撞上的场景。比如有人提了一个关于monorepo的场景:他的仓库里同时有前端和后端代码,用了一套规则配置,但两个目录的检查标准完全不一样。我原来是"全局规则只支持一套配置",他来了之后我加了按路径拆分配置的能力,path_rules可以让不同目录使用不同规则集。
第二个改进是JSON 报告输出。原来工具只有人类可读的文本输出和 GitHub 评论两种结果,有用户在做自研的代码质量平台,希望 CI 跑完后能直接把结构化结果发到他们的服务里。我在 CLI 里加了一个--format json参数,输出包含规则名、级别、文件路径、行号、建议修复方案的标准 JSON,方便二次集成。
第三个改进是关于规则模板库。社区里有人贡献了一套针对不同语言的常用规则模板,覆盖 Go、Python、JavaScript、TypeScript 等语言最常见的代码异味。现在新用户不需要从零开始写规则,直接引用模板就能跑起来一套基础检查,这大大降低了工具的初始使用成本。
6.3 后续规划:从"评论者"变成"协作伙伴"
当前阶段,open-code-review 仍然是一个基于规则的检查工具,它擅长发现"已经定义过的问题",但不擅长发现"从未见过的问题"。我接下来想探的方向有两个:
一是引入增量学习的能力。当开发者在讨论区标记某条评论为"误报"时,工具能把这个反馈记录下来,后续对类似的模式自动降权或者不再报告。这个功能做好了,工具会越来越懂团队的语言习惯。
二是提升对结构性变更的感知。比如一个大文件被拆成多个模块,字段名做了系统性重命名,这类重构操作在 diff 上很难通过逐行规则发现,但可以通过 AST 级别的跨文件对比来感知。目前这个方向的实验代码还在很早期阶段,但我觉得它会是代码评审工具的下一个分水岭。
7. 实测数据、发布经验和最终体会
最后聊一点运营层面的经验,以及我自己在这个项目里的最终感受。
7.1 四个月真实使用数据
从工具成形到开源,我在自己所在团队和三个朋友团队的仓库里做了内测,累计跑了 400 多次评审,积累了下面这份数据:
| 项目 | 数据 |
|---|---|
| 评审 PR 总数 | 426 |
| 发现的问题总数 | 1,873 |
| error 级别问题 | 312 |
| warning 级别问题 | 1,561 |
| 被采纳的修复比例 | 71% |
| 平均单 PR 评审耗时 | 14 秒 |
| 误报率(用户手动标记) | 8.6% |
有意思的是,被采纳修复的比例(71%)比我想象中高。我原本预计这种自动化评论的采纳率可能只有 40% 左右,因为人会对机器有天然的抵触。后来复盘发现,高采纳率主要归功于两条:一是错误级别必须足够"硬",比如密钥泄露、危险函数调用,这些问题一旦报出来,开发者不敢不改;二是评论要带修复建议,并尽量精确到行,省去了开发者自己定位的时间。
7.2 开源发布要注意的几个小事
如果你也打算发布一个开源工具,有几个细节可能会帮到你。首先是LICENSE 一定要开箱即带,不要拖到有人问才补,这是项目能否被企业使用的第一关。我一开始放的是 MIT 协议,后来收到一个企业用户的 issue 问"能不能商用来着",才意识到协议选型本身就影响项目的适用人群。
其次是版本号语义。CLI 工具最好遵循 SemVer,0.x 到 1.0 的边界要清楚,否则用户看到"0.4.2 到 0.5.0 的 breaking change"时会对项目的稳定性产生怀疑。我自己的经验是:0.x 版本不承诺任何 API 稳定性,但每个 minor 版本升级时在 changelog 里明确标注 breaking change,这比"突然改个接口还不说"要友好得多。
最后是CI 配置本身的 CI。一个代码评审工具如果自己没有在 CI 里跑起来,很难说服别人它是可依赖的。我在开源仓库的 workflow 里同时跑了单元测试、集成测试和 open-code-review 自检,这样每次 PR 合并前都会经历一轮"吃自己的狗粮",既验证了工具的稳定性,也让用户看到一个真实的使用示例。
7.3 我的最终体会
做 open-code-review 这个项目,让我重新理解了代码评审的本质。它不是一个技术问题,而是一个信任问题。开发者不拒绝工具,拒绝的是那些不懂上下文、只会拿规则大棒乱打人的"机器人评审员"。一个靠谱的代码评审工具,应该像团队里那个对代码很较真、但每次提意见都有理有据的同事——它不替代人做判断,而是帮人把最耗精力的那部分脏活先干完。
如果你所在的团队正在纠结"代码评审流于形式"或者"大 PR 根本 review 不过来",与其逼着大家每周开评审会议、写一堆没人看的规范文档,不如试试把那些可以用规则描述的问题交给工具去盯。也许不一定非要自研一个完整的工具,但先把团队里"能用规则表达的问题"列一个清单,然后让自动化工具去逐个落地,这件事本身的价值就很高了。
到最后,"open-code-review" 对我来说已经不只是仓库里那一堆代码,它提醒我的一件事是:任何工具的开发,最重要的都是先搞清楚"人真正需要被帮什么忙",而不是一上来就想着怎么把技术做得多花哨。