单一存储库:请

图片


本文是为OTUS教育项目中的DevOps实践和工具课程的学生准备的。




您应该选择一个单一存储库,因为它在您的团队中促进的行为是透明和集体责任,尤其是随着团队的成长。 无论如何,您都必须投资工具,但是当默认行为是您希望在命令中看到的行为时,总会更好。


我们为什么要谈论这个?


马特·克莱因(Matt Klein)写了一篇文章, “莫诺雷波斯:请不要!” (翻译者的评论:在中心“ Monorepositories:请不要”上的翻译 )。 我喜欢Matt,我认为他非常聪明,您应该阅读他的观点。 他最初在推特上发布了推文:


图片


翻译:
在今天的元旦,我将争论单一存储库的荒谬之处。 2019年开始被忽视。 本着这一精神,我为您提供一项调查。 谁是狂热分子? 支持者:
- 单一存储库
-
- 错误的调查/


我的回答是:“我确实是这两个人。” 除了讨论哪种Rust药物外,让我们弄清楚为什么我认为他对单一存储库是错误的。 关于你自己的一些。 我是Chef软件的CTO。 我们有大约100名工程师,大约11至12年的代码库以及4种主要产品。 此代码的一部分在多存储库(我的起始位置)中,部分在单存储库(我的当前位置)中。


在开始之前:在这里引用的每个论点都将应用于两种存储库。 我认为,没有技术原因可以选择一种或另一种类型的存储库。 您可以使任何方法起作用。 我很高兴谈论这一点,但是我对其中一个优于另一个的人工技术原因不感兴趣。


我同意马特观点的第一部分:


因为大规模存储,单一存储库将解决多存储库所解决的所有相同问题,但同时又使您的代码具有强大的一致性,并且需要付出巨大的努力来提高版本控制系统的可伸缩性。


无论选择单一存储库还是多存储库,都必须解决相同的问题。 您如何发布版本? 您的更新方法是什么? 向后兼容? 跨项目依赖性? 可以接受哪些建筑风格? 您如何管理构建和测试基础架构? 列表是无止境的。 随着您的成长,您将解决所有问题。 没有免费的奶酪。


我认为Matt的论点与我所尊重的许多工程师(和经理)的观点相似。 从在组件上工作的工程师或在组件上工作的团队的角度来看,这是发生的。 您会听到类似的声音:


  • 代码繁琐-我不需要所有这些垃圾。
  • 这很难测试,因为我必须检查所有不需要的垃圾。
  • 使用外部依赖关系更加困难。
  • 我需要自己的虚拟版本控制系统。

当然,所有这些观点都是合理的。 在两种情况下都会发生这种情况-在聚合存储库中,我有自己的东西,除了组装所需的东西...我可能还需要其他东西。 因此,我“只是”创建了签​​出整个项目的工具。 还是我用子模块创建了一个假的Mono存储库。 我们可以整日走动。 但是我认为Matt的论点没有找到主要原因,而我几乎完全赞成单一存储库:


它引起沟通并显示问题。


当我们共享存储库时,实际上会产生一个协调和透明性问题。 这对应于我们对团队的思考方式(尤其是各个参与者对团队的思考方式):我们对特定的组件负责。 我们相对隔离地工作。 界限固定在我的团队和我们正在研究的组件上。


由于架构的复杂性,一个团队无法再单独管理它。 很少有工程师将整个系统掌握在头脑中。 假设您控制一个公共组件A,该组件由命令B,C和D使用。团队A重构,改进了API,还更改了内部实现。 结果,更改向后不兼容。 您会提出什么建议?


  • 查找所有使用旧API的地方。
  • 有没有无法使用新API的地方?
  • 您可以修复和测试其他组件以确保它们不会损坏吗?
  • 这些团队可以立即检查您的更改吗?

请注意,这些问题与存储库的类型无关。 您将需要找到B,C和D团队。您需要与他们交谈,找出时间,了解他们的优先级。 至少我们希望您这样做。


没有人真的想要这样做。 这比仅修复该死的API的乐趣要少得多。 所有这一切都是人为的和困惑的。 在存储库中,您可以简单地进行更改,对正在使用此组件的人员(可能不是B,C或D)进行检查,然后继续。 团队B,C和D可以仅保留其当前版本。 当他们意识到您的天才时,它们就会被更新!


在单个存储库中,默认情况下转移了责任。 团队A更改了组件,并且如果不小心,会立即破坏B,C和D。这导致B,C和D出现在门A上,想知道为什么团队A破坏了装配。 这告诉A他们不能跳过我的上面的列表。 他们应该谈论他们将要做什么。 B,C和D可以移动吗? 如果B和C可以,但是D与旧算法的副作用密切相关,该怎么办?


然后,我们需要讨论如何摆脱这种情况:


  1. 支持多种内部API,而旧算法将被标记为过时,直到D停止使用它为止。
  2. 支持多种版本的发行版,一个具有旧界面,一个具有新界面。
  3. 延迟发布对A的更改,直到B,C和D都可以接受它为止。

假设我们选择1,几个API。 在这种情况下,我们有两段代码。 旧的和新的。 在某些情况下非常方便。 我们返回旧代码,将其标记为已弃用,并商定使用D命令删除它的时间表,这对于poly和mono-repository本质上是相同的。


要发布多个版本,我们需要一个分支。 现在我们有两个组件-A1和A2。 团队B和C使用A2,而D使用A1。 我们需要准备好发布每个组件,因为在D继续进行之前,可能需要安全更新和其他错误修复。 在存储库中,我们可以将其隐藏在感觉良好的长期分支中。 在单一存储库中,我们将代码强制放入新模块中。 D小组仍然必须对“旧”组件进行更改。 每个人都可以在这里看到我们要付出的代价-我们现在拥有两倍的代码,并且适用于A1和A2的所有错误修复都应同时应用于它们两个。 通过在存储库中使用分支的方法,这隐藏在“摘樱桃”之后。 我们认为成本较低,因为没有重复。 从实际的角度来看,代价是相同的:您将创建,发布和维护两个基本相同的代码库,直到可以删除其中一个。 不同之处在于,在单一存储库中,这种疼痛是直接的并且是可见的。 这甚至更糟和更好。


最后,我们到达第三点。 释放延迟。 A所做的更改可能会改善A团队的生活。这很重要,但并不紧迫。 我们可以忍受吗? 在存储库中,我们正在推动此操作以合并工件。 当然,我们谈论的是D团队。只是继续使用旧版本,直到赶上来! 这建立了一个胆小游戏。 团队A继续致力于其组件,而忽略了团队D使用的版本已经过时的事实(这对于团队D是一个问题,他们很愚蠢)。 同时,如果D团队完全谈论A团队对代码稳定性的粗心态度,那他们就不好说了。 几个月过去了。 最后,D团队决定看一下升级选项,但是对A的更改更多。 A团队几乎不记得他们何时以及如何打破D。更新会更加痛苦,并且需要更长的时间。 它将进一步发送给优先级堆栈。 直到那天,直到我们在A中遇到安全问题,这迫使我们建立分支。 A团队必须及时返回,找到D稳定的时刻,在那里解决问题并准备发布。 这实际上是人们做出的选择,这是迄今为止最糟糕的选择。 只要我们可以彼此忽略,这对于A和D团队都似乎是一件好事。


在单一存储库中,第三个确实不是一个选择。 您被迫以两种方式之一来处理这种情况。 您需要查看拥有两个发布分支的成本。 了解如何保护自己免受破坏向后兼容性的更新。 但最主要的是: 您无法避免艰难的交谈。


以我的经验,当团队规模扩大时,就不可能再牢记整个系统了,这是最重要的部分。 您需要提高系统中分歧的可见性。 您必须积极工作,以使团队将视线从其组件上移开,并关注其他团队和消费者的工作。


是的,您可以创建工具来尝试解决多存储库的问题。 但是我在大型企业中教授连续交付和自动化的经验告诉我以下内容:不使用其他工具的默认行为是您期望看到的行为。 存储库的默认行为是隔离,这就是重点。 单一存储库的默认行为是责任分担和透明,这就是重点。 在这两种情况下,我都将创建一个可以消除尖角的工具。 作为领导者,我每次都会选择一个单一的存储库,因为工具必须加强我想要的文化,而这种文化来自于微小的决定和团队的日常工作。

Source: https://habr.com/ru/post/zh-CN453958/


All Articles