为什么我更喜欢基于主干的开发


如今,像Git这样的分布式版本控制系统已经 "赢得了版本控制的战争"。当DVCS越来越受欢迎的时候,我经常听到的一个论点是围绕着用Git这样的VCS进行分支和合并是多么容易。然而,我是基于主干的开发(TBD)的大粉丝,我想告诉你为什么。

在基于主干的开发中,所有的开发者都在一个单一的分支上工作(比如 "main")。你可能读过或听过Martin Fowler或Dave Farley谈论过它。当我和Dave一起工作时(大约在Git迅速成为 "常用 "版本控制系统的时候),我真正看到了基于主干的开发对团队的好处,特别是在一个正在开拓持续交付的环境中。

相比之下,分支模式鼓励开发者为每一个功能、错误修复或增强创建单独的分支。虽然分支似乎是隔离变化和减少风险的合理方法,但有几个因素让我对基于主干的开发更放心。

1.速度和效率
在基于主干的开发中,整个团队在一个单一的分支上工作。这种模式允许更快的集成和更少的合并冲突。这就是字面上的 "持续集成(CI)",最初是由极限编程的实践建议的。虽然现在我们说CI时往往是指 "每次提交时在团队服务器上运行你的构建和测试",但CI的真正含义是定期整合你的代码。根据定义,生活在不同分支上的代码是不集成的。这些分支存在的时间越长,把它们合并到主代码库中就越有挑战性。在一个不受其他开发者改动影响的独立分支上开发你的修正和改进可能看起来很快,但你仍然必须在某个时候支付这个成本。定期将小的改动整合到你的代码中,通常比在较长一段时间结束时进行大的合并要少一些痛苦。

2.更大的代码稳定性
基于主干的开发鼓励频繁提交,这导致了更小和更容易管理的变化。怎么做,为什么?就像我们不希望从长期存在的分支中进行大的合并一样--我们提交修改的时间越长,我们的提交就越有可能与别人的修改发生冲突。通过频繁地拉入其他开发者的修改,以及频繁地推送工作代码的小修改,我们知道代码库是稳定的,可以工作的。当然,如果我们有一个CI服务器,为每个提交的代码运行构建和测试,这种 "稳定和工作 "的假设就更容易检查。如果构建过程中出现问题,我们也必须停止提交,并专注于修复该构建。在构建已经损坏的情况下继续频繁地推送小的提交,对任何人都没有好处。

在分支模式中,大量的、不频繁的合并会带来错误,由于变化的规模太大,很难识别和解决。你是否曾经在别人合并了自己的大型工作后,将主干合并到你的分支中,发现你的代码不再工作了?当你做了一大堆修改,而别人也做了一大堆不同的或重叠的修改时,你可能要花很多时间来追踪为什么你的测试会失败或应用程序不能按你的期望工作。而这是假设你真的有可靠的测试覆盖率,可以告诉你有问题。

3.加强团队合作
我最喜欢在团队成员之间分享知识的方式是结对编程。我知道并不是每个人都喜欢或者有条件这样做(尤其是现在越来越多的人在远程工作,但如果是这样,可以去看看JetBrains的Code With Me)。如果你不结对,那么至少你想在同一个代码上工作,对吗?如果你们都在自己的分支上工作,你们就不是在合作了。你们是在竞争。看谁能最快地把自己的代码放进去。为了避免被别人的代码修改踩到。

如果你们都在同一个分支上工作,你们往往对正在进行的修改有更好的认识。这种方法促进了更大的团队合作和知识共享。相反,分支可以创造一个孤岛式的工作环境,大家都在独立工作,导致团队内部出现知识差距。

4.改进持续集成和交付(CI/CD)实践
Dave Farley的《持续交付》一书,以及他的博客文章和视频,都认为 "基于主干的开发与持续集成和持续交付(CI/CD)实践是内在兼容的"。

在基于主干的模式中,持续集成变得更加直接,因为你的代码经常被提交到主干,而这是你的CI环境运行构建和测试的分支。那里的任何故障都会被发现并及时解决,从而减少了讨厌的故障的风险。通常很容易追踪到哪些修改导致了问题。如果问题不能被立即修复,你可以回溯引起问题的具体变化。

现在我们应该知道快速反馈回路的重要性--当你更快地发现问题时,你可以更快地找到原因,你也可以更快地修复它。这就提高了你的软件质量。

持续交付也在一个基于主干的开发环境中蓬勃发展。成功的持续交付有赖于拥有一个始终处于可部署状态的代码库的能力。基于主干的开发方法通过促进频繁的提交、频繁的集成和对所有这些集成的测试来确保这一点。在任何时候引入的少量变化使软件更容易部署和测试。

相比之下,实施有效的CI/CD可能会因为分支模式而更加复杂和耗时。虽然我们很容易想到 "好吧,我在我的分支上运行我的构建和所有的测试",但实际上你并不是在每次提交时都进行集成。在合并(或重新发布)时,你才开始看到任何集成问题。你在 "CI "分支上运行的所有这些测试,根本不是在测试任何一种集成。

合并和测试来自不同分支的代码会带来延迟和潜在的错误,这使得拥有一个构建管道的一些好处被剥夺。


5.减少技术债务
寿命长的分支往往会导致 "合并地狱",即一个分支(如 "主")和另一个分支(如你的特性分支)之间的差异如此之大,以至于合并成为一场噩梦。这可能会导致技术债务,因为你可能会采用快速修复的方法来解决合并冲突,或者接受IDE的建议来解决合并问题,但你并不完全理解。在基于主干的开发中,频繁的合并和较小的变化使其更容易管理并减少技术债务的积累。

总而言之
我个人认为,基于主干的开发有明显的优势,我在采用这种方法的团队中亲身体验过。然而,它需要开发团队内部的一种思维方式,一种文化。你需要经常将其他开发者的修改合并到你自己的代码中。你需要经常提交小的修改,这就要求你只修改代码的小部分,并进行增量修改,这可能是一个难以习惯的习惯。结对编程、全面的自动化测试和可能的代码审查是帮助所有团队采用相同方法和文化的关键实践。

基于主干的开发,以严谨的方式进行,简化了开发过程,加强了团队协作,提高了代码的稳定性,支持高效的CI/CD实践,并可能导致更少的技术债务。如果你一直在使用基于分支的模式,适应这种方法可能是一个挑战,但长期的好处是值得的。如果你想改变你的团队的工作方式,转向基于主干的开发模式,你可能还想阅读Dave的文章,解决基于主干开发的障碍