作为一名在海外知名代码托管平台工作的工程师,代码审查是我日常工作中最重要的内容之一。过去八年里,我审查了 7000 多个 Pull Request,也就是我们常说的 PR。为什么会有这么多?因为代码审查对构建优秀软件至关重要,而多一双眼睛,往往就能发现那些你原本可能忽略的问题。
我一直认为,代码审查是工程工作中最关键的环节之一。事实上,每当我看到队友提交了待审查的 PR,我通常都会优先放下手头的工作,转而审查他们的修改。毕竟,他们的 PR 已经通过了持续集成(CI)的层层检查,也达到了作者自己认定的“完成”标准,因此很可能比我正在编写的代码更接近可发布状态。与其继续把时间投入到自己尚未完成的代码上,我更愿意先帮助他们的代码顺利推进。

越早给出反馈,问题就越早得到解决。例如:“这里可能为 nil,从而导致错误”“这看起来像一个 N+1 查询”“如果能给这个方法加上签名会更好”。这些反馈越早出现,错误就能越快被消除,功能也能越快发布。
本文将分享一套高效代码审查方法,包括如何查找待审查 PR、如何优化代码审查流程、如何给出高质量审查意见,以及如何在 AI 编码工具普及的背景下继续保障代码质量。希望这些经验能帮助我们写出更好的代码。
什么是代码审查?
严格来说,代码审查指的是协作者通过代码托管平台上的 PR 审查功能,对 PR 中提出的更改发表评论、表示批准,或在 PR 合并前要求进一步修改。
在我看来,PR 是一次对话的开始。作者提交 PR,本质上是在表达:“我认为这比我们现有的代码更好。”而代码审查,正是改进产品实现方式的绝佳机会。作为代码审查者,我的职责是与作者反复讨论,通过提问、质疑假设,并充当“第二双眼睛”,帮助他们进一步改进代码。
为什么代码审查很重要?
我从其他代码审查者的视角中学到了很多。多次收到别人感谢我及时审查代码的积极反馈后,我也意识到,我的审查意见同样帮助团队成员提升了水平。简而言之,代码审查确实有效,而晋升往往需要你展现出自己的影响力。
代码审查之所以重要,是因为它有助于知识交流,也能提升产品发布速度。代码审查的成果清晰可见,同事和管理者都可以通过它了解你的能力与专业水平。尤其是在处理复杂或有争议的变更时,代码审查更能体现你的沟通能力。
因此,在代码审查中充分阐述你的观点,不仅可以引导产品未来的技术方向、规避安全隐患,也会对你的职业发展产生积极影响。
如何优化代码审查流程?
如何查找待审查的 PR
我几乎每天都会查看代码托管平台的通知收件箱。它是我浏览器中少数几个固定标签页之一,因此我随时都能看到它。无论是在等待 CI 更新、任务切换间隙、一天刚开始工作时,还是其他任何空档,我都会查看一下收件箱。大多数需要我审查的 PR,都是从那里发现的。
在一些海外技术团队中,团队通常会有一个固定的企业协作频道作为“大本营”,那里也是分享待审查 PR 的好地方。这也是我发现 PR 的主要途径之一。
我也很喜欢使用代码托管平台与企业协作工具的集成功能,在团队频道中订阅与团队相关的新 PR。为了筛选频道中显示的 PR,我会使用团队专属标签,并执行类似这样的订阅命令:
/subscribe your/repo pulls +label:"your-team-label"
我还喜欢用类似下面的查询,搜索可能需要审查的待处理 PR:
is:open archived:false is:pr org:your-org -is:draft team-review-requested:your-org/relevant-codeowner-team
通过这个查询,我可以找到组织内未归档、非草稿,且已请求相关代码所有者团队审查的 PR。我通常会省略 review:required 这个搜索限定符,因为即使团队成员已经审查过,我也仍然想查看这些 PR。毕竟,代码审查不仅能帮助作者,也能帮助我及时了解自己负责代码的变化。
使用审查团队管理通知
你肯定不希望代码变更通知多到让团队里的每个人都觉得“这不是我的责任”。这会导致两种糟糕结果:PR 要么无人审查而长期搁置,要么因为关键审查人员被大量通知淹没而过早合并。无论哪种情况,都会影响产品质量。
如果条件允许,我建议精简代码所有者团队的数量,以便更好地管理通知。这样,你收到的 PR 通知就不会只是噪音,而是真正值得你审查的内容。庞大、包罗万象的代码所有者团队可以作为备选方案,但不应成为自动审查请求的首选对象。
请保持仓库中的 CODEOWNERS 文件结构清晰,并明确划分代码边界,以减少通知数量,帮助审查者避免通知疲劳。
另一种限制团队通知的方式,是创建一个“值班响应团队”,并通过自动化根据日程安排添加和移除团队成员。这样,团队可以专注于日常代码库开发,而指定的值班人员则会收到团队服务范围内 PR 的通知。例如,你可以使用值班管理系统的 API 确定某一天的值班人员,然后使用平台 API 客户端库添加或移除团队成员。
通过自动化统一代码审查标准
仓库级别的配置与自动化,例如 CODEOWNERS 文件和分支保护规则,有助于在团队之间强制执行统一的代码审查流程。至于其他标准,比如 PR 中哪些内容值得评论,则仍然需要由人来维护。
请记录团队内部的代码审查流程,确保所有负责审查代码或提交 PR 的人都了解:如何提交 PR 并获得审查、预期的审查周期,以及有哪些自动化工具可以帮助简化审查流程。
对于研发团队来说,如果希望把代码审查与需求、排期、开发、测试、发布以及知识沉淀连接起来,也可以借助 PingCode 这类智能化研发管理工具,将研发过程中的数据、流程和经验统一沉淀下来,帮助团队更好地跟踪 PR 状态、复盘审查质量,并持续提升研发效能。
有些团队使用项目看板来跟踪哪些 PR 需要审查。我发现这种方法对管理共享 API 的团队非常有效,因为这类 API 经常会被团队外部人员修改。另一些团队则完全依赖代码托管平台的通知。当代码所有权范围清晰,并且团队能严格遵守审查 PR 的纪律时,这种方法也同样有效。
对于涉及产品、研发、测试、运营等多角色协作的团队,也可以使用 Worktile 这类通用项目协作系统,通过任务、项目、文档、日历、甘特图等能力,把 PR 审查之外的沟通、排期和跟进事项统一管理起来,减少信息分散带来的协作成本。
如果你的团队遵循一套特有流程,自动化还可以帮助你向团队外部人员传达预期。例如,如果许多其他团队都依赖你们团队的审查,你可以使用机器人,在任何请求你们团队审查的 PR 中自动留言,告知作者大概何时会收到回复。
什么样的代码审查才算好?
好的代码审查应当提升代码的清晰度,并推动代码向比最初版本更好的状态发展。
作为代码审查者,清晰沟通至关重要。你需要明确区分:哪些评论只是个人偏好,哪些问题会阻碍代码通过。为了提升代码审查效率,也为了让自己的意思更清楚,请尽量提供你建议采用的方法示例。如果示例来自同一个代码库,那就更好了——这能鼓励代码实现保持一致,也能让你的建议更有说服力。
相比之下,糟糕的代码审查往往缺乏清晰度。例如,不加任何评论地一概批准或拒绝,会让 PR 作者怀疑审查是否足够认真。即使只是在批准时重申你对作者意图的理解,也能帮助确认你和作者是否达成了同样的理解。
如果代码审查没有明确说明某项建议是否必须在当前 PR 中完成,作者的体验也会很糟糕。指出现有但未修改的代码需要重构,或者提醒作者还需要处理额外用例,这些都很好;但关键是要说明:这些是否是最终批准的前提。如果即使不采纳你的建议,这个 PR 也可以合并,请务必明确说明。有时,保持较小的变更范围,并将这些修改作为单独的 PR 提交,会更加安全。
下面是一条具体且清晰的代码审查意见:
我注意到你的新方法与文件中现有方法的风格一致,都接受了 X 个参数。参数过多会降低可读性,也可能暗示函数承担了过多职责。你觉得是否可以在后续 PR 中重构这个方法以及其他现有方法,减少参数数量?
这条评论的优点在于:
- 提供了具体细节;
- 引用了具体代码或问题;
- 提出了可行的解决方向;
- 提供了理由或解释。
另一方面,下面这些评论就有改进空间。
“我不喜欢这个。”
审查者不喜欢什么?是否有可以明确提出的替代方案?
可以改为:
这一行承担了较多逻辑,我们能否简化一下,以提高可读性?
我认为这里可能会触发 N+1 查询,从而导致性能问题。
我们能否使用团队首选框架提供的方案,而不是编写自定义实现?
“这样做行不通。”
为什么行不通?
可以改为:
这样做行不通,因为 X。请参考相关问题:[问题链接]。
之前在 [PR 链接] 中尝试过这种方式,但由于 X 原因没有成功。
如果 X 出现问题,你可以尝试 [替代方案]。
“我认为这修复了一个漏洞。”
这个表达方向很好,但如果能补充更多上下文,例如相关问题链接,就会更清楚。
可以改为:
我认为这可以解决 [问题链接] 中的问题。
这是否修复了 [问题链接] 中提到的错误?
这看起来像是我们在构建失败时遇到的那个 bug。感谢修复!
如何进行有效的代码审查?
提问
我认为,PR 作者最了解自己提交的更改细节。我可以基于自己的经验,例如在大型单体应用、前端类型系统或高流量数据库方面的工作经验,指出我看到的问题;但我更信任作者的回答。我相信他们通常比我更了解具体细节。
我也喜欢提出一些与代码假设相关的问题。例如:他们处理的数据结构是什么样的?是否存在不符合这种结构的数据?代码能否妥善应对这种情况?代码是否会消耗大量资源?性能表现如何?
作为代码审查者,我最喜欢的回复,是作者提供一个自动化测试,用来验证代码在这些场景下的行为。其次,我也很喜欢作者提供经验数据,例如来自数据仓库的查询结果或监控平台图表,来说明这些场景为什么不会造成问题。
作为 PR 作者,我也非常乐意收到问题。当有人提问时,我就有机会解释为什么我对自己的更改有信心,并在必要时引用相关问题、查询或图表。这也让我有机会与他人分享知识和经验。不仅审查者能看到我的回复,未来那些想查找既往决策背景的人,也能看到这些讨论。
提供肯定
除了提问,对你认同的 PR 部分发表评论也是一种很好的做法。这些评论可以表明你已经阅读并理解了变更内容,也可以验证代码中的某些假设。比如:
看起来这与本模块其他类中使用的模式一致。
谢谢你添加这个测试!
这比以前更容易阅读了。
就我个人经验而言,收到这样的评论会让人感觉很好。代码审查有时会让人精疲力尽。当我要回应来自各方的问题和建议时,如果能收到一些不要求我做额外工作、而是支持并认可已有成果的评论,那会是一种很大的鼓励。
注意偏见与假设
我们很容易因为对某位作者本人,或对其修改代码区域的既有印象,而影响自己的审查判断。你可能已经习惯某个人在某个领域工作,或认为他们资历深厚,于是想当然地相信他们知道自己在做什么。但人都会犯错。你认真查看他们的修改,通过提问验证他们的假设或确认你自己的假设,就有机会在部署前发现问题。
我非常重视编写测试,因为测试可以消除一部分主观偏见。当你编写测试来检查代码是否正常工作时,你不必完全依赖作者的说法,只需要查看测试是否通过即可——当然,前提是测试本身没有问题。😅
我非常鼓励初级开发者在代码审查中向高级开发者提问,即使他们觉得自己的问题很傻,或者答案似乎显而易见。如果你觉得某件事并不明显,那很正常。对其他人来说,也可能同样不明显。提出问题,并给回答者留出空间写下答案,就能为后来者留下宝贵的知识。
批准,还是不批准?
我会把自己的审查视为一道“门槛”:它可能会阻止其他人改进我们的产品。因此,我会慎重考虑是否批准。
我通常会有一些个人偏好,也会提出一些希望作者采纳的可选修改建议,但我不会仅仅因为这些建议没有被采纳就拒绝批准。如果我对某个 PR 有建议,但这个 PR 本身不会破坏生产环境、不会对用户造成负面影响,也不会引发其他问题,我会批准它,并附上我的评论。作者可以选择在合并前采纳我的反馈,也可以在后续分支中继续改进。
在代码审查时,请始终牢记你建议的重要性。为了采纳你的建议而延误开发进度,真的值得吗?是否值得让作者经历完整流程:看到你的反馈、进行建议修改、等待 CI、再次审查、部署,最后合并?如果缺少某项建议并不会给其他人带来不便,那就把是否以及何时修改的决定权交给作者。
“请求更改”这个选项会阻止 PR 被合并,直到审查者回来并批准为止。我很少使用它,因为它通常显得过于强硬。我相信自己的团队知道何时可以批准 PR,因此队友的批准足以代替我的批准。同样,我也相信 PR 作者会尊重并认真考虑我的反馈,而不是因为其他人已经批准就忽略我的意见、直接合并。
我几乎只会在一种情况下选择“请求更改”:我认为存在紧急安全问题,并且担心作者在合并前看不到我的顾虑。
AI 编码工具时代,为什么代码审查仍然重要?
AI 编码工具通常内置了各种安全措施,用来避免生成错误或不安全的代码。但这并不意味着我们可以放松警惕。
作为主导代码审查的人工审查者,你是最后一道防线。无论代码是否由 AI 辅助生成,都应该以同样严谨的态度进行审查。
如何最大限度地利用代码审查?
先审查自己的代码
某位海外高级软件工程师曾教我,在请别人审查 PR 之前,先自己检查一遍。我也建议你这样做。
先通读一遍自己的 PR,对那些不太明显的改动添加注释;如果这些改动出现在别人的 PR 中,而你可能会提出问题,那就提前在自己的 PR 中说明。自我审查还能帮助你判断 PR 是否过大,是否应该拆分。
友情提示:如果你希望保持 PR 简洁,可以使用自动化工具为 PR 添加标签,以提示其复杂度和规模。
乐于接受合并后的审查
如果我在其他人有机会审查之前就合并了 PR,我仍然欢迎他们继续审查。如果我的 PR 破坏了某些功能,或者产生了意想不到的后果,在 PR 上留下评论会形成线索,帮助未来的读者追踪当时发生了什么。
如果我收到对已合并 PR 的审查意见,我会像 PR 合并前一样处理这些反馈。也许我会添加一条评论解释自己的观点;也许我会提交额外的 PR,迭代最初发布的代码;也可能会创建新的 issue,记录后续还需要完成的工作。
使用草稿 PR
创建新的 PR 时,你可以选择将其设置为草稿。我经常使用草稿状态来表明当前是否需要审查。例如,如果必要的 CI 构建失败了,或者我还没有完成工作,我会让 PR 保持草稿状态。
我也希望其他人的 PR 能合理使用草稿状态:如果一个 PR 是草稿,我会假设作者还没准备好接受审查;如果它被标记为“已准备好审查”,我就会假设作者只需要获得足够的批准,就可以部署这个 PR。
草稿状态表示 PR 尚未完成。因此,在解决合并冲突或处理审查者反馈时,我会把 PR 移回草稿状态。如果我需要修改代码,我会先将 PR 标记为草稿,以免给已经审查过代码的人造成额外负担。当我再把它改回“已准备好审查”状态时,平台会通知这些审查者,提醒他们可以再次查看。
保持宽容与善意
有句谚语说:“用蜂蜜比用醋更能招来苍蝇。”我希望自己的 PR 能得到别人审查,所以我也喜欢回复 PR 下的评论,尤其是在我不同意审查者观点时。即使我不回复审查评论,通常也会用点赞表示同意或认可,用爱心表示感谢。
我希望审查者相信,他们的建议不会被遗忘。因此,我会通过评论让他们了解进展。如果我同意他们的建议,比如进一步重构现有代码,我会明确表达认同,但也会说明为什么不打算在当前 PR 中完成这项改动。当我在后续 PR 中采纳他们的反馈时,我会附上链接,让审查者知道他们的建议已经得到落实。
我会在后续 PR 中标记他们,并在实现建议更改的同时添加说明,例如:
此更改解决了 @某位审查者 在 <之前的 PR URL> 中提出的反馈。
这样既能为其他读者提供背景信息,也能向最初的审查者致谢,感谢他们提出想法。
当你信守承诺,在后续分支中处理反馈时,就能与审查者建立信任。今后他们也会更放心地批准你的 PR,因为他们知道你不会把事情半途搁置。
总结:高质量代码审查值得长期投入
代码审查对产品质量的重要性不容低估,尤其是在 AI 生成代码越来越普遍的时代。在我的职业生涯中,很多时候正是因为多了一双眼睛,才发现了漏洞,或避免了事故。
无论是日常审查、流程优化,还是构建自动化支持,代码审查都绝对值得投入时间。对开发者来说,现在认真审查 PR,远比之后处理已经上线的问题更快,也更省心。
文章包含AI辅助创作,作者:liu,如若转载,请注明出处:https://docs.pingcode.com/baike/5245519