Monorepo 与 Multi-Repo:代码存储库策略的优缺点

通过 Git 托管和管理代码有两种主要策略:monorepo 与 multi-repo。这两种方法各有优缺点。

尝试免费演示

我们可以对任何语言的任何代码库使用任何一种方法。您可以将这些策略中的任何一个用于包含少量库到数千个库的项目。即使涉及几个团队成员或数百人,或者您想托管私有或开源代码,您仍然可以根据各种因素选择 monorepo 或 multirepo。

每种方法的优点和缺点是什么?我们什么时候应该使用其中一个?让我们一探究竟吧!

什么是回购?

存储库(repository 的缩写)是项目中所有更改和文件的存储,使开发人员能够在整个开发阶段对项目资产进行“版本控制”。

我们通常指的是 Git 存储库(由 GitHub、GitLab 或 Bitbucket 提供),但该概念也适用于其他版本控制系统(例如 Mercurial)。

monorepo 方法和多 repo 方法。🚀 探索本指南中的每一个 ⬇️点击推文

什么是 Monorepo?

monorepo 方法使用单个存储库来托管组成公司项目的多个库或服务的所有代码。在最极端的情况下,来自一家公司的整个代码库——跨越各种项目并用不同的语言编码——都托管在一个存储库中。

Monorepo 的好处

将整个代码库托管在单个存储库上有以下好处。

降低进入壁垒

当新员工开始为公司工作时,他们需要下载代码并安装所需的工具才能开始工作。假设项目分散在许多存储库中,每个存储库都有其安装说明和所需的工具。在这种情况下,初始设置将很复杂,而且文档通常不完整,需要这些新团队成员向同事寻求帮助。

monorepo 简化了问题。由于有一个包含所有代码和文档的位置,您可以简化初始设置。

位于中心的代码管理

拥有一个存储库可以让所有开发人员看到所有代码。它简化了代码管理,因为我们可以使用单个问题跟踪器来观察整个应用程序生命周期中的所有问题。

例如,当问题跨越两个(或更多)子库且依赖库上存在错误时,这些特征很有价值。对于多个存储库,可能很难找到发生问题的代码段。

最重要的是,我们需要确定使用哪个存储库来创建问题,然后邀请和交叉标记其他团队的成员来帮助解决问题。

但是,使用 monorepo,定位代码问题和协作排除故障都变得更容易实现。

无痛的应用范围重构

在创建代码的应用程序范围重构时,多个库将受到影响。如果您通过多个存储库托管它们,管理所有不同的拉取请求以保持它们彼此同步可能是一个挑战。

monorepo 可以轻松地对所有库的所有代码执行所有修改,并在单个拉取请求下提交。

更难打破相邻的功能

使用 monorepo,我们可以为所有库设置所有测试,以便在修改任何单个库时运行。因此,在某些库中进行更改的可能性已最小化对其他库的不利影响。

团队共享发展文化

尽管并非不可能,但使用 monorepo 方法,在不同团队之间激发独特的亚文化变得具有挑战性。由于它们将共享相同的存储库,因此它们很可能将共享相同的编程和管理方法并使用相同的开发工具。

Monorepo 方法的问题

对我们所有的代码使用单个存储库有几个缺点。

更慢的开发周期

当库的代码包含破坏性更改,导致依赖库的测试失败时,还必须在合并更改之前修复代码。

如果这些库依赖于其他团队,他们正忙于处理其他任务并且无法(或不愿意)调整他们的代码以避免破坏性更改并通过测试,则新功能的开发可能会停滞。

更重要的是,该项目很可能仅以公司中最慢团队的速度开始推进。这种结果可能会使速度最快的团队成员感到沮丧,为他们想要离开公司创造条件。

此外,库还需要为所有其他库运行测试。要运行的测试越多,运行它们所需的时间就越多,从而降低了我们迭代代码的速度。

需要下载整个代码库

当 monorepo 包含公司的所有代码时,它可能会非常庞大​​,包含数千兆字节的数据。要为托管在其中的任何库做出贡献,任何人都需要下载整个存储库。

处理庞大的代码库意味着我们硬盘驱动器上的空间使用不当,并且与它的交互速度较慢。例如,执行 git status 或使用正则表达式在代码库中搜索等日常操作可能比使用多个 repos 花费的时间多几秒甚至几分钟。

未修改的库可能是新版本

当我们标记 monorepo 时,其中的所有代码都被分配了新的标记。如果此操作触发新版本,则存储库中托管的所有库都将使用标签中的版本号新发布,即使其中许多库可能没有任何更改。

分叉更难

开源项目必须让贡献者尽可能容易地参与进来。使用多个存储库,贡献者可以直接前往他们想要贡献的项目的特定存储库。但是,对于托管各种项目的 monorepo,贡献者必须首先引导他们进入正确的项目,并且需要了解他们的贡献可能如何影响所有其他项目。

什么是多回购?

多存储库方法使用多个存储库来托管公司开发的项目的多个库或服务。在最极端的情况下,它将在其存储库下托管每组最小的可重用代码或独立功能(例如微服务)。

多重回购的好处

独立于所有其他图书馆托管每个图书馆提供了许多好处。

独立库版本控制

标记存储库时,它的整个代码库都被分配了“新”标签。由于存储库中只有特定库的代码,因此可以独立于其他地方托管的所有其他库对库进行标记和版本控制。

每个库都有一个独立的版本有助于定义应用程序的依赖树,允许我们配置要使用的每个库的版本。

独立服务版本

由于存储库仅包含某些服务的代码而没有其他任何内容,因此它可以有自己的部署周期,与访问它的应用程序取得的任何进展无关。

该服务可以使用快速发布周期,例如持续交付(在通过所有测试后部署新代码)。一些访问该服务的库可能使用较慢的发布周期,例如那些每周只发布一次新版本的库。

帮助定义整个组织的访问控制

只有参与开发库的团队成员需要添加到相应的存储库并下载其代码。因此,应用程序中的每一层都有一个隐式访问控制策略。与库相关的人员将被授予编辑权限,其他人可能无法访问存储库。或者他们可能被授予阅读权,但没有编辑权。

允许团队自主工作

团队成员可以独立于所有其他团队设计库的架构并实现其代码。他们可以根据库在一般上下文中的行为做出决策,而不受来自某些外部团队或应用程序的特定要求的影响。

订阅时事通讯

想知道我们是如何将流量增加超过 1000% 的吗?

加入 20,000 多名其他人的行列,他们会收到我们的每周时事通讯,其中包含 WordPress 内幕技巧!

现在订阅

多回购方法的问题

使用多个存储库可能会引起几个问题。

库必须不断地重新同步

当发布包含重大更改的库的新版本时,需要调整依赖于该库的库以开始使用最新版本。如果库的发布周期比其依赖库的发布周期快,它们之间可能很快就会变得不同步。

团队需要不断追赶以使用其他团队的最新版本。鉴于不同的团队有不同的优先级,这有时可能难以实现。

因此,无法赶上的团队最终可能会坚持使用依赖库的过时版本。这一结果将对应用程序产生影响(在安全性、速度和其他考虑方面),跨库的开发差距可能只会越来越大。

五月碎片团队

当不同的团队不需要互动时,他们可能会在自己的孤岛中工作。从长远来看,这可能会导致团队在公司内产生他们的亚文化,例如采用不同的编程或管理方法或使用不同的开发工具集。

如果某个团队成员最终需要在不同的团队中工作,他们可能会遭受一些文化冲击并学习一种新的工作方式。

Monorepo 与 Multi-Repo:主要区别

这两种方法最终都处理相同的目标:管理代码库。因此,他们必须解决相同的挑战,包括发布管理、促进团队成员之间的协作、处理问题、运行测试等。

他们的主要区别在于他们对团队成员做出决定的时间安排:无论是前期单回购还是后期多回购。

让我们更详细地分析这个想法。

由于所有库在多存储库中都是独立版本控制的,因此发布具有重大更改的库的团队可以通过将新的主要版本号分配给最新版本来安全地进行。其他组可以让他们的依赖库坚持旧版本,一旦他们的代码被改编就切换到新的。

这种方法让每个负责的团队决定何时调整所有其他库,他们可以随时进行调整。如果他们做得太晚并且发布了新的库版本,缩小库之间的差距将变得越来越困难。

因此,虽然一个团队可以快速且频繁地迭代他们的代码,但其他团队可能无法赶上,最终产生分歧的库。

另一方面,在 monorepo 环境中,我们不能发布一个库的新版本来破坏其他库,因为它们的测试将失败。在这种情况下,第一个团队必须与第二个团队沟通以合并更改。

这种方法迫使团队在必须对单个库进行更改时完全适应所有库。所有团队都被迫相互交谈并共同达成解决方案。

厌倦了没有答案的低于 1 级的 WordPress 托管支持?试试我们世界一流的支持团队!查看我们的计划

结果,第一个团队将无法像他们希望的那样快速迭代,但是跨不同库的代码永远不会开始出现分歧。

总而言之,多回购方法可以帮助在团队之间创造一种“快速行动并打破常规”的文化,在这种文化中,灵活的独立团队可以以他们的速度产生他们的输出。相反,monorepo 方法有利于意识和关怀的文化,团队不应该被抛在后面独自处理问题。

混合 Poly-As-Mono 方法

如果我们不能决定是使用多存储库还是 monorepo 方法,还有一种中间方法:使用多个存储库并使用一些工具来保持它们同步,使其类似于 monorepo 但具有更大的灵活性。

Meta 就是这样一种工具。它在子目录下组织多个存储库,并提供一个命令行界面,可以同时对所有存储库执行相同的命令。

元存储库包含有关哪些存储库构成项目的信息。通过元克隆这个存储库将递归地克隆所有需要的存储库,使新的团队成员可以更轻松地立即开始他们的项目。

要克隆一个元存储库及其所有定义的多个存储库,我们必须执行以下操作:

元 git 克隆 [元回购网址]

Meta 将为每个存储库执行一个 git clone 并将其放在子文件夹中:

克隆元项目

克隆元项目。(图片来源:github.com/mateodelnorte/meta)

此后,执行 meta exec 命令将在每个子文件夹上执行该命令。例如,在每个存储库上执行 git checkout master 是这样完成的:

元执行“git checkout master”

混合 Mono-As-Poly 方法

另一种方法是通过用于开发的 monorepo 管理代码,但将每个库的代码复制到其独立的存储库中进行部署。

这种策略在 PHP 生态系统中很普遍,因为 Packagist(主要的 Composer 存储库)需要一个公共存储库 URL 来发布包,并且不可能指明该包位于存储库的子目录中。

鉴于 Packagist 的限制,PHP 项目仍然可以使用 monorepo 进行开发,但它们必须使用多 repo 方法进行部署。

为了实现这种转换,我们可以使用 git subtree split 执行脚本或使用执行相同逻辑的可用工具之一:

  • Git 子树拆分器
  • Git子拆分
  • Monorepo 拆分的 GitHub 操作

谁在使用 Monorepo 和 Multi-Repo

几家大型科技公司偏爱 monorepo 方法,而其他公司则决定使用 multi-repo 方法。

谷歌、Facebook、Twitter 和 Uber 都公开担保采用 monorepo 方法。微软运行着地球上最大的 Git monorepo 来托管 Windows 操作系统的源代码。

另一方面,Netflix、亚马逊和 Lyft 是使用多回购方法的著名公司。

在混合 poly-as-mono 方面,Android 更新多个存储库,这些存储库像 monorepo 一样进行管理。

在混合 mono-as-poly 方面,Symfony 将其所有组件的代码保存在一个 monorepo 中。他们将其拆分为独立的存储库进行部署(例如 symfony/dependency-injection 和 symfony/event-dispatcher。)

Monorepo 和 Multi-Repo 的示例

GitHub 上的 WordPress 帐户托管了 monorepo 和 multi-repo 方法的示例。

WordPress 块编辑器 Gutenberg 由几十个 JavaScript 包组成。这些包都托管在 WordPress/gutenberg monorepo 上,并通过 Lerna 进行管理,以帮助将它们发布到 npm 存储库中。

Openverse 是开放许可媒体的搜索引擎,其主要部分托管在独立的存储库中:前端、目录和 API。

Monorepo vs Multi-Repo:如何选择?

对于许多开发问题,对于应该使用哪种方法没有预定义的答案。不同的公司和项目将根据其独特的条件从一种或另一种策略中受益,例如:

  • 代码库有多大?它是否包含千兆字节的数据?
  • 有多少人会在代码库上工作?大约是 10、100 还是 1,000?
  • 会有多少个包裹?大约是 10、100 还是 1,000?
  • 团队在给定时间需要处理多少个包?
  • 包的耦合度如何?
  • 是否涉及不同的编程语言?它们是否需要安装特定的软件或特殊的硬件才能运行?
  • 需要多少部署工具,设置起来有多复杂?
  • 公司的文化是什么?是否鼓励团队合作?
  • 团队知道如何使用哪些工具和技术?

您应该为代码库采用哪种方法?🤔 在这里了解更多👇点击推文

概括

托管和管理代码有两种主要策略:monorepo 与 multi-repo。monorepo 方法需要将不同库或项目的代码 – 甚至来自公司的所有代码 – 存储在单个存储库中。并且多存储库系统将代码划分为单元,例如库或服务,并将它们的代码托管在独立的存储库中。

使用哪种方法取决于多种条件。这两种策略都有几个优点和缺点,我们刚刚在本文中详细介绍了所有这些。

您对 monorepos 或 multi-repos 有任何疑问吗?请在评价部分留下您的意见!

通过以下方式节省时间、成本并最大限度地提高站点性能:

  • 来自 WordPress 托管专家的即时帮助,24/7。
  • Cloudflare 企业集成。
  • 全球受众覆盖全球 28 个数据中心。
  • 使用我们内置的应用程序性能监控进行优化。

所有这些以及更多,都在一个没有长期合同、协助迁移和 30 天退款保证的计划中。查看我们的计划或与销售人员交谈以找到适合您的计划。

相关文章