如何高效地做代码审查:一位资深工程师的20年经验总结

Published by rcdfrd on 2025-09-15

原文作者:Matthias Endler


我从事代码审查工作已经超过二十年了。如今,我大约50%到70%的工作时间都在以某种形式审查代码,这也是我主要的职责之一,与系统设计并列。

随着时间推移,我逐渐摸索出一套高效的代码审查方法。现在的我,关注的重点与刚入行时已大不相同。


一、从“大局”出发:别只盯着语法和格式

低质量的代码审查往往视野狭窄,只关注语法、风格或细枝末节,而忽略了代码的可维护性和可扩展性。

高质量的审查,不仅看“改了什么”,更关注:

  • 这些改动解决了什么问题?

  • 是否会引发新的问题?

  • 是否与系统整体架构协调?

    我特别喜欢关注没有被改动的代码行,它们往往藏着真正的故事。比如,开发者常常忘记更新相关模块或文档,这可能引发 bug、破坏向后兼容性,甚至带来安全隐患。

    审查时,我会问自己:

  • 这段代码如何融入整个系统?

  • 它与其他模块如何交互?

  • 是否会影响未来的开发计划?

  • 是否引入了更好的抽象?

    这些问题,更多关乎系统设计,而非代码本身。忽视“大图景”,系统终将因不良变更而变得脆弱。


二、命名至关重要:它是代码的“门面”

我在审查中,花大量时间思考命名是否恰当。

命名虽难,却极其关键。好的命名是代码质量的基石,而糟糕的命名则是“代码异味”的信号,会成倍增加认知负担。

例如,以下代码:

fn update_player_stats(player: Player, bonus_points: i32, level_up: bool) -> Player {
    let usr = player.username.trim().to_lowercase();
    let updated_score = player.score + bonus_points;
    let l = if level_up { player.level + 1 } else { player.level };
    let l2 = if l > 100 { 100 } else { l };

    Player { username: usr, score: updated_score, level: l2 }
}

变量名如 usrl2 含义模糊,逻辑难以追踪。

而优化后的版本:

fn update_player_stats(player: Player, bonus_points: i32, level_up: bool) -> Player {
    let username = player.username.trim().to_lowercase();
    let score = player.score + bonus_points;

    let level = if level_up { player.level + 1 } else { player.level };
    let level = if level > 100 { 100 } else { level };

    Player { username, score, level }
}

每个变量名都清晰表达了其含义,最终变量名与结构体字段一致,极大提升了可读性。


三、敢于说“不”:拒绝低质量代码是种责任

我经常不得不拒绝某些提交,这从来不容易。毕竟,作者付出了努力,渴望被认可。

但不要为了让别人开心而妥协质量。要客观、清晰地解释原因,并提供更好的替代方案。拒绝的是代码,不是人。

在开源项目中,尤其需要“守门人”。如果每次都说“先合并以后再改”,技术债将迅速堆积,项目终将失控。

敢于说“不”,是资深工程师的担当。


四、代码审查是“人与人的沟通”

审查不仅是技术活动,更是团队协作与信任建设的过程。

我通常会尽量与作者面对面或结对审查前几次 PR,了解彼此的沟通风格,建立信任。

当沟通出现障碍时,不妨回到这种方式,人与人的理解,往往比代码本身更重要。


五、审查是“迭代”的过程,而非一次性通过

很多人希望“今天提 PR,明天就合并”。但高质量的代码往往需要多轮审查。

我的流程通常是:

  1. 第一轮:关注整体设计与架构

  2. 第二轮:深入细节与边界情况

  3. 如有必要,继续微调与优化

    目标不是“快”,而是“对”。审查的意义,就在于共同打磨出高质量的代码。


六、做个“好人”:尊重与建设性胜过一切

即使意见不同,也要保持尊重与礼貌。避免说“你错了”,而是说“如果是我,可能会这样做”。

多使用“苏格拉底式提问”:

  • “这样会不会破坏现有流程?”

  • “你有没有考虑其他替代方案?”

  • “如果传入空数组,会发生什么?”

    让人乐于接受你的反馈,是一种能力。

    偶尔加上一句“这个想法很棒”,会让作者感受到被认可,积极反馈同样重要。


七、尽可能“跑一遍代码”

纸上得来终觉浅。我习惯把代码拉下来,跑一跑、测一测、甚至故意“搞破坏”。

尤其对 UI 改动、错误提示等用户可见变更,本地运行能发现很多静态代码审查遗漏的问题。

跑完后,我会回退改动,把发现的问题记录下来,作为评论提交。


八、主动沟通你的“可用性”

代码审查常成为开发瓶颈。如果你没时间审查,务必提前告知作者,避免对方空等。

我也在努力养成这个习惯:主动告知“我这几天很忙,可能无法及时 review”,这是对他人时间的尊重。


九、把审查当作学习的机会

每次审查,我都尝试学点新东西:新语法、新设计模式、新库,甚至别人解决问题的思路。

审查不是“浪费时间”,而是团队共同成长的最佳途径。


十、别做“格式警察”:把琐事交给工具

格式化、空格、换行,这些交给 linter 和 formatter 就好。

把精力留给真正重要的事:逻辑正确性、设计合理性、可维护性。

问问自己:“这会影响功能吗?会让未来的开发者困惑吗?”如果不会,就让它去吧。


十一、关注“为什么”,而非“怎么做”

审查时,多关注作者做出变更的动机与背景,而非单纯指出“你怎么这么写”。

一条好的评论,应该:

  • 指出潜在问题

  • 提供替代方案

  • 解释原因与后果

  • 给出文档或资料链接

    这样的反馈,作者会感激你,也会真正成长。


十二、别怕问“蠢问题”

不懂就问,比假装懂要好得多。

你不懂的地方,别人也可能不懂。提问不仅能帮助你理解,也能促使作者反思自己的设计是否合理,甚至发现遗漏的文档或注释。

提出好问题,是一种超能力。


十三、定期征求对你“审查风格”的反馈

偶尔问问作者:

  • “我是否太苛刻或太琐碎?”

  • “我的反馈对你有帮助吗?”

  • “你觉得我哪些地方可以改进?”

    让别人“审查你的审查”,是提升审查能力的捷径。


写在最后:好的审查,是一种艺术

代码审查,不只是技术活动,更是沟通、学习、成长与信任的过程。

它需要耐心、尊重、洞察力与责任感。

愿我们都能成为那种让人“期待”收到 feedback 的审查者。


翻译整理自 Matthias Endler 的博客文章《How To Review Code》,略有删减与调整,以便中文阅读。