28、代码审查:Review 流程设计,Checklist 制定,自动化审查工具(Reviewable, Gerrit)
代码审查这件事,我做了十几年。说实话,刚入行那会儿我觉得这玩意儿就是浪费时间——自己写的代码自己最清楚,干嘛还要别人看?直到有一次,我提交了一个看似完美的内存池实现,结果被同事揪出一个隐蔽的 double-free 漏洞。嗯,从那以后,我再也不敢小看代码审查了。
今天咱们聊聊 C++ 大型项目里的代码审查。这不是简单的「你帮我看看代码」,而是一整套工程实践。我会从流程设计、Checklist 制定,再到工具选型,把这块讲透。
为什么大型项目必须搞代码审查?
你想想看,一个 C++ 项目动辄几十万行代码,光靠一个人把关,迟早出问题。我见过太多项目,前期不搞 Review,后期 bug 修到崩溃。
代码审查的核心价值有三点:
- 缺陷拦截:越早发现 bug,修复成本越低。我统计过,Review 阶段发现一个 bug 的成本,比线上修复低 10 倍不止。
- 知识传递:新人通过 Review 学习老手的写法,老手也能从新人的视角发现盲区。
- 代码一致性:确保整个团队的代码风格、架构思路保持一致,而不是各写各的。
核心观点:代码审查不是「找茬」,而是「共同提升」。好的 Review 文化,能让团队的整体代码质量上一个台阶。
Review 流程设计:从提交到合并
流程这东西,太复杂没人愿意走,太简单又形同虚设。我个人习惯用「三阶段模型」:
阶段一:提交前自检
开发者自己先过一遍。我要求团队在提交前做三件事:
- 运行本地单元测试,确保不破坏已有功能
- 用 clang-format 格式化代码,统一风格
- 用 clang-tidy 做静态分析,扫一遍常见问题
这一步做好了,Reviewer 的负担能减轻 50%。
阶段二:Review 流程
提交后,系统自动分配 Reviewer。我建议至少两个人:一个熟悉业务逻辑的,一个熟悉底层架构的。流程如下:
- Reviewer 收到通知,开始审查
- 提出意见,开发者修改
- 循环直到所有问题解决
- Reviewer 批准,代码合并
这里有个坑:Review 周期不能太长。我曾经见过一个 Review 拖了两周,结果开发者都忘了自己写了啥。我建议 24 小时内给出初步反馈,48 小时内完成。
阶段三:合并后跟踪
代码合并后,CI 系统自动跑集成测试。如果挂了,自动回滚并通知相关人员。这一步很多人忽略,但其实是最后一道防线。
我的经验:Review 流程要「自动化优先」。能交给机器做的,别让人做。比如代码风格检查、静态分析,这些都应该在提交前自动完成。
Checklist 制定:别漏掉关键点
光有流程还不够,你得有个 Checklist。不然 Reviewer 容易漏掉重点。我整理了一份 C++ 项目的核心 Checklist,分享给你:
| 类别 | 检查项 | 说明 |
|---|---|---|
| 正确性 | 边界条件处理 | 空指针、数组越界、整数溢出 |
| 正确性 | 资源管理 | RAII 是否用对?有没有内存泄漏? |
| 正确性 | 并发安全 | 锁的粒度是否合理?有没有死锁风险? |
| 可维护性 | 命名规范 | 变量名是否自解释?有没有魔法数字? |
| 可维护性 | 函数长度 | 单个函数不超过 50 行,超过就拆 |
| 性能 | 不必要的拷贝 | 传参用 const& 还是值?移动语义用了吗? |
| 性能 | 容器选择 | vector 还是 list?unordered_map 还是 map? |
| 测试 | 单元测试覆盖 | 新代码有没有对应的测试用例? |
这个 Checklist 不是死的。每个项目可以根据自身特点调整。比如做嵌入式开发的,要加「内存对齐」检查;做游戏引擎的,要加「热路径优化」检查。
注意:Checklist 别搞太长。超过 20 项,Reviewer 就会开始敷衍。我建议控制在 10-15 项,覆盖最关键的点就行。
自动化审查工具:Reviewable 与 Gerrit
手动 Review 效率有限,得靠工具。我重点讲两个:Reviewable 和 Gerrit。
Reviewable:轻量级,适合小团队
Reviewable 是一个基于 GitHub 的代码审查工具。它的特点是轻量、易上手。我个人很喜欢它的「逐行评论」功能——你可以直接在代码的某一行上写评论,开发者能精准定位问题。
举个例子:
// 开发者提交的代码
void processData(const std::vector<int>& data) {
for (size_t i = 0; i < data.size(); ++i) {
// 处理逻辑
}
}
// Reviewer 的评论
// 建议用 range-based for 循环,更简洁
// for (const auto& val : data) { ... }
Reviewable 还支持「自动合并」——当所有问题都解决后,代码自动合并到主分支。这个功能很实用,省去了手动操作的时间。
Gerrit:重量级,适合大型项目
Gerrit 是 Google 开发的代码审查系统,很多大型项目(比如 Android)都在用。它的核心特点是「严格的权限控制」和「细粒度的审查流程」。
Gerrit 的工作流是这样的:
- 开发者把代码 push 到 Gerrit 的「待审查」分支
- Gerrit 自动触发 CI 构建和静态分析
- Reviewer 在 Web 界面上审查,给出评分(+1, +2 等)
- 达到一定分数后,代码才能合并
Gerrit 的评分机制很有意思:
- +1:看起来还行,但我不确定
- +2:没问题,我批准
- -1:有问题,需要修改
- -2:严重问题,不能合并
我建议团队设置「至少两个 +2 才能合并」的规则。这样能避免单人决策的偏差。
我的建议:小团队用 Reviewable,大团队用 Gerrit。如果你用的是 GitLab,它的内置 MR 功能也够用。别为了用工具而用工具,适合自己团队才是最好的。
知识体系:代码审查的核心逻辑
说了这么多,我画了一张图,帮你理清代码审查的知识体系:
避坑指南:我踩过的那些坑
最后,分享几个我亲身踩过的坑,希望能帮你少走弯路:
- Review 流于形式:我曾经在一个项目里,Reviewer 只看代码格式,不看逻辑。结果上线后出了严重的并发问题。记住,Review 的核心是逻辑正确性,不是代码风格。
- Review 范围太大:一次 Review 超过 400 行代码,效果会急剧下降。我建议每次提交控制在 200-300 行,超过就拆成多个提交。
- 忽视负面反馈:有些开发者收到负面评论会抵触。我见过最极端的情况,两个人因为一个变量命名吵了一周。我的建议是:对事不对人,用数据说话。
- 工具依赖过度:自动化工具能帮你发现 80% 的问题,但剩下的 20% 需要人来判断。比如「这个设计是否合理?」「这个接口是否易用?」——这些机器看不出来。
总结一下:代码审查不是走过场,而是一项需要认真对待的工程实践。流程要清晰,Checklist 要实用,工具要选对。最重要的是,培养团队的 Review 文化——每个人都愿意花时间帮别人看代码,也愿意接受别人的意见。
好了,这一章就到这里。代码审查这块,说到底就是「人 + 流程 + 工具」的配合。你回去可以看看自己团队的 Review 流程,有没有可以优化的地方。如果有问题,欢迎随时交流。