我们如何在基于主干的持续部署开发团队中使用 GitHub PR。
在快节奏的世界中,越来越多的团队拥有微服务架构,并正在转向持续部署和基于主干的开发。对于我们客户的一个团队来说,这意味着没有功能分支,总是对 main 提交,频繁推送(每小时多次,每 1-4 次提交),并且这些更改在 20-30 分钟后登陆生产。
在结对编程、没有功能分支以及这种持续变化的情况下,代码审查似乎是多余的或极其困难,几乎没有工具支持。当没有要区分的功能分支时,您将如何在此设置中使用 GitHub 的 Pull Request 审查功能?
我们发现,不仅代码审查很有价值,GitHub 的 Pull Request 审查功能在使用我们称为“Reverse Pull-Requests”的方法的过程中发挥了关键作用。
上下文
该产品是业务中其他应用程序使用的一组 API,最重要的是他们的电子商务平台,每月支持数百万美元的收入。该团队由具有广泛经验的开发人员组成。Antony 一直是球队的球员兼教练,自球队成立以来就为球队设定了建筑方向并指导球队。Lukasz 的加入是为了帮助在客户的特定技术堆栈上实现 Antony 设想的我们微服务架构的事件驱动元素。
该团队有意识地决定通过每个微服务拥有一个 Git 存储库来最大限度地提高灵活性,从而解决存储库自动化带来的挑战。每个微服务都是 10 行代码,不包括任何样板、配置和测试代码。该团队每天都应用结对/暴民编程。
源代码存储库的数量已经超过了团队中对的数量,甚至是开发人员的数量。这意味着任何时候任何配对都在同一个存储库上工作的可能性很小。
为了应用持续交付,有必要在整个测试范围内(例如,单元、组件、CDC、端到端)通过高质量的测试来实现高代码覆盖率。
有些东西不见了
这一切都运行得非常顺利,交付业务价值的速度比公司中的任何其他团队都快,而且敏捷度如此之高,以至于团队几乎可以立即根据要求改变开发过程。
但是,缺少的是更广泛地了解应用于代码的更改。由于微服务的数量(大约 40 个)以及新功能通常是通过创建新的微服务来实现的事实,一些开发人员有一段时间没有看到很多代码库。这导致项目在设计模式、代码约定甚至代码质量方面变得不一致。
问题是,我们如何提高代码质量和一致性?我们如何通过将代码中其他地方使用的解决方案更多地暴露给更多团队成员来改善知识共享?
代码审查可以成为答案吗?
我们已经有一个名为“技术聊天”的每日论坛,用于讨论设计、技术挑战或分享新颖的解决方案。然而,这缺乏可以从例行审查代码中获得的偶然学习。
大多数经验丰富的团队成员都熟悉代码审查——尤其是使用 GitHub 拉取请求,这似乎是我们问题的完美解决方案。除了,GitHub 拉取请求假定您有一个要合并到主分支的功能分支。这显然是我们没有的!
有些人可能会争辩说,在配对时,不需要进行代码审查。我们始终相信测试想法,所以我们决定试一试,看看我们学到了什么。我们在其中一个正在研究的用户故事上进行了尝试,看看我们能学到什么。
然而,挑战在于如何将代码交付到生产环境并持续进行代码审查。好吧,我们知道我们不能脱离功能分支,因为这会破坏我们能够工作的速度。所以,我们需要另一个解决方案!
反向拉取请求
如果按照设计,我们不在分支上工作——我们能做些什么呢?这是安东尼提出的问题。Lukasz 给出了答案:我们可以在工作开始之前创建一个分支,而不是合并到 main/master 的分支。拉取请求从 master/main 合并到新创建的分支中。这为我们提供了与传统拉取请求相同的差异,以及捕获我们对所选解决方案的想法和反馈的工具。我们将其命名为反向拉取请求。
这是它的工作原理。
一对、一群人或一个开发人员不断地向 master/main 提交并推送提交,以便更改可以通过管道进入生产。一旦故事在功能上完成,并且两人对代码感到满意,该工作就可以进行审查了。
然后在工作开始之前从提交中创建一个分支。这本质上是工作开始之前的 master/main 快照。
当该分支被推送时,会提出一个拉取请求以将主分支合并到该新分支(而不是相反,通常情况下)。
然后进行所有常见的公关相关活动,例如评论、讨论、代码更改等。
PR diff 遵循 main/master 中的更改,而 PR 中的对话显示了正常的讨论和更改。在整个过程中,这一次,我们仍然在 PR 进行期间将所有由此产生的更改交付到生产环境中。完成后,我们关闭 PR 而不进行合并(显然——没有必要)。这会保留所有评论以供将来参考——对于审计尤其有用。
一种被探索但从未成功的做法是在开始工作时创建快照分支,以便它在那里并为 PR 做好准备。这可能是你可以尝试的。
反向拉取请求本质上是一种替代方式,允许您利用 GitHub 的代码审查功能,同时保留通过仅提交和推送到主/主来实现的流程。但是,在某些情况下,这可能不适合您。
限制
尽管我们发现反向 PR 很有用,但我们知道它们并不实用或不适用于许多团队,尤其是那些使用单一存储库的团队,或者当开发人员与存储库的比率足够高以至于在同一代码库上工作如此频繁时很难将一对与另一对所做的更改分开。
因此,有理由问,如果同时在同一个 repo 中进行多个更改怎么办?如何审核合并后的更改?如果非故事提交是在故事的中途进行的,例如横切重构或库更新怎么办?太多不相关的变化混合在一起会使差异变得不连贯。
这些都是很好的问题。由于上述工作方式,我们不必经常处理这些情况。如果一个或两个不相关的更改进入 PR,这实际上并不是什么大问题。提出 PR 的人可以随时在 PR 评论中提及更改的作者。然而,有一些可能的方法来处理上述情况(尽管我们还没有尝试过)。
为避免以后的更改混淆差异,您可以使用合并两个非主分支的 PR。想象一下,在相关更改之前(如上所述)从提交创建一个新分支,并从最后一个相关提交创建另一个分支。然后可以提出 PR 以将后一个分支合并到前一个分支中,以实现所需的差异。
这种方法可能会从审查的角度迎合该场景,但不会保留反馈的任何后续改进。这可以在新的 PR 中捕获。我们很想听听您对如何处理此案的想法。
Cherry Picking 是将 PR 限制为仅进行相关更改的另一种潜在解决方案。我们将把它留给读者来探索这种方法在他们的环境中的可行性。另一种方法可能是在 IDE 中过滤掉提交,就像在 IntelliJ IDEA 中一样。
结论
首先,在尝试了这种方法之后,我们发现代码审查很有帮助,即使是结对工作!是的!结对编程满足了您从代码审查中获得的大部分内容,但并非总是如此,也不是所有的好处。
我们发现代码审查有些不同。这就像有一个不同的视角,比配对时更少的偏见。你有一双崭新的眼睛,因为你不太可能做出改变。或者,如果您是第一批配对的团队成员之一,那么您会带来一双更新鲜的眼睛,而您已经过了几天才离开这个故事。或者,你发现事情有点偏离了轨道。
它还为团队成员提供了相互学习的偶然机会,了解问题是如何解决的,发现与他们正在解决的问题相似的问题,并将共享的解决方案整合到库中或应用类似的模式或他们以前不知道的语言功能。
对我们来说,反向拉取请求提高了代码质量、知识转移和一致性。它为我们的日常技术聊天提出了主题,从而达成了新的约定,并以一种非阻塞的方式改进了整体设计。
代码是连续交付的,因此价值正在实现——更多的是确保代码处于易于理解和将来更改的状态的问题。
由于这些原因,在尝试了反向 PR 方法后,团队决定保留这种做法。它已成为团队工作方式不可或缺的一部分,在反向 PR 上获得两次批准是该团队完成定义的最后一项。
虽然此处描述的解决方案似乎适用性有限,但在正确的环境中,它可能会帮助您获得类似的结果。如果您认为这可能对您有用,请将其视为实验,就像任何更改一样。小规模地应用它,首先,看看你学到了什么。
热门跟贴