作者:Kief Morris
译者:冬哥
原文:https://infrastructure-as-code.com/book/2021/01/02/pull-requests.html
前 言
Github 引入了Pull Request拉取请求(简称PR)实践和相关的支持功能,使运行开源项目的人更容易接受来自他们信任的提交者群体之外的贡献。
Committer是被信任的主体,可以定期更改代码库。但是需要评估来自随机外部人员的更改,以确保其有效,不会使项目朝着不需要的方向发展,并且符合风格和质量标准。外部人员将他们提出的变更打包为拉取请求,Committer可以轻松地将其作为一个单元进行审查和管理,然后再将其合并到代码库中。
(图 1:拉取请求流程)
尽管拉取请求旨在更容易地接受来自团队外部不受信任的人的贡献,但现状是很多团队对内部人员使用拉取请求。这种做法已经变得如此普遍,以至于许多人将其视为默认的“最佳”实践。有些人认为没有其他方法可以确保代码得到评审,因为他们从未见过其他任何东西。
然而,拉取请求会牺牲性能,包括交付时间和质量。当管理来自未知人员的变更风险时,这是一个值得做出的牺牲。外部人员可能不了解你项目的愿景和方向。他们在测试、代码质量和风格方面可能没有相同的习惯和规范。但是,你自己团队成员内部应该共享这些规范。
针对自己团队成员的代码变更采用拉取请求,就像让你的家人通过机场安全检查站进入你家一样,这是针对不同问题的昂贵解决方案。
使用持续集成而不是拉取请求
软件交付过程应该针对流程和质量进行优化。将变更前置保持在较短的时间,并在变更引入问题时提供快速反馈。这是支持持续集成(CI)的想法。CI 是在每个人的代码上不断合并和测试他们的做法。
(图 2:持续集成过程)
“当他们工作时”是必不可少的。作为团队成员,你不会等到完成某个功能或故事后才将代码集成到主干中。相反,你经常 - 至少每天一次 - 将你的代码置于健康状态,通过测试并将其与其他人的当前工作一起集成到主干中。
每次推送变更时,CI 构建作业都会自动测试项目的主干。这意味着在投入太多时间之前,你会立即发现你正在做的事情是否与另一个人正在做的事情发生冲突。当你认为已经完成了一个故事或功能,却发现必须回去解决并重做这几天的努力,会很糟糕。
(图 3:每次推送时都在集成代码上运行测试)
拉取请求的麻烦
拉取请求会延迟集成。当完成工作,认为已准备好与团队其他成员的工作进行集成时,你创建一个拉取请求并等待有人对其进行审核。只有在其他人审查通过变更后,才会将其与主干集成。
如果团队成员快速审查和集成拉取请求,这仅比 CI 慢一点。也许他们会在你每次推送的30 分钟内回复并审核,将你的代码变更与主干集成,并针对它运行自动化测试。因此,你可能会在 30-40 分钟左右之后发现与其他人的工作发生冲突。
(图 4:拉取请求与 CI 的反馈延迟)
在实践中,没有多少团队能在 30 分钟内可靠地解决拉取请求。在等待某人审查你的变更时,你可以切换到另一个任务或开始处理新的修改。当发现存在问题时,你需要切换回原始更改,从而中断了当前的工作流程。
另一方面,有效的 CI 构建应该在推送集成代码后的几分钟内完成测试 - 在我们的场景中最多 10 分钟。你几乎会立即发现该冲突,因此可以对其进行调查和修复。
在从测试完全集成的代码中获得反馈之前,你无需打断其他人的工作来要求他们对其进行审查。正如我将很快解释的那样,你可能仍然需要有人审核变更。但是你可以利用更快的周期时间来提交、集成和测试自己的代码,以便在要求他们审查之前进行多项更改。
即使团队中的每个人都很快地改变了拉取请求,典型的做法是等到完成功能或故事的工作,然后再将拉取请求与主干集成。大多数团队平均需要超过一天的时间来开发一个故事。因此,典型的拉取请求流程不满足持续集成的最低要求,即至少每天集成每个人的工作。
每天数次以编码、拉取、测试、推动和从集成测试中获取反馈的节奏工作会令人兴奋,而拉取请求在节奏中引入人为延迟,不可能产生这种兴奋感。
审查代码更改更好的方法
当 CI 与拉取请求的话题出现时,不可避免地会有人站出来为拉取请求辩护,以获取其他团队成员对更改的反馈。
必须有第二双眼睛(如果不是更多)查看代码更改。人类会发现测试没有发现的问题,尤其是与可维护性和设计相关的问题。让人们审查彼此的代码还有助于团队在编码风格、编程习惯和质量要求等规范上趋于一致。在某些情况下,例如受监管的环境,需要由第二人审查每个更改。
然而,最近拉取请求的流行似乎导致一些人认为没有其他方法可以用来审查代码变更。以下是你可以使用的一些实践,而不会中断持续集成反馈周期。请记住,完全可以根据需要进行多个实践的组合。
(图 5:配对以实现即时、持续的代码审查)
-
结对编程:没有任何形式的代码审查比结对编程更有效。反馈是即时的,因此使用它进行改进的可能性要高得多。如果有人在你编写代码时告诉你有更好的方法,那么你可以立即停止、学习并以更好的方式编写代码。如果有人在一天后告诉你,你可以将其记录下来以备将来参考。但是要让你停止当前的工作并回去重做你已经完成的工作,这会成为一个严重的问题。
-
定期审查:如果合规性没有明确要求进行审查,则可能不需要为每个代码更改设置一个门禁。你可能有定期的、预定的审查,例如每周,来检查自上次审查以来的代码更改。这作为小组练习尤其有效,因为它创建了对话,帮助人们学习和塑造团队的编码规范。
-
流水线审批:如果你的团队使用持续交付流水线将变更交付到生产,可以包括一个阶段,要求有人授权变更进行。这在概念上类似于拉取请求,因为它是交付过程中的一个门禁,但当你将门禁放在代码集成和自动化测试之后。这样做意味着人们只花时间审查已经在技术上被证明是正确的代码。
(图 6:在集成和测试之后审查更改)
结论
拉取请求与持续集成的不同之处在于,在编写代码变更之后但在将其与主线集成之前,需要人工审查代码更改。这会延迟从已完全集成代码的自动化测试中获取到反馈。
使用持续集成,代码要么在编写时(结对)进行审查,要么在集成和测试之后进行审查。针对集成和测试变更的循环进行优化,意味着你可以更频繁地运行此循环。更频繁的编码和集成循环鼓励开发人员进行更小更频繁的提交,从而提高质量和流程。