monorepo
是一个版本控制的代码存储库,包含许多项目。虽然这些项目可能是相关的,但它们在逻辑上通常是独立的,并由不同的团队运行。
有些公司将所有代码放在一个存储库中,供所有人共享。Monorepos
可以达到巨大的尺寸。例如,谷歌理论上拥有有史以来最大的代码存储库,每天有数十个提交,超过80 tb。其他使用 Monorepos
的公司还有微软、Facebook和Twitter。
Monorepos有时被称为单块存储库,但它们不应该与单块体系结构混淆,后者是用于编写自包含应用程序的软件开发实践。这方面的一个例子是处理网站、API端点和后台作业的 Ruby on Rails monolith
。
与monorepo
相反的是multirepo
,其中每个项目都保存在一个完全独立的、版本控制的存储库中。multirepo
——是我们大多数人在开始一个新项目时所做的。
从 multi
到 monorepo
就是将所有的项目移动到一个存储库中。
当然,这只是开始。当我们开始重构和整合时,困难就来了。
$ mkdir monorepo
$ git init
$ mv ~/src/app-android10 ~/src/app-android11 ~/src/app-ios .
$ git add -A
$ git commit -m "My first monorepo"
Multirepos
不是微服务的同义词;一个不需要另一个。事实上,我们稍后将讨论将monorepos
和微服务相结合的公司。一个monorepo
可以托管任意数量的微服务,只要您仔细地设置了用于部署的持续集成和交付(CI/CD)管道。
乍一看,在monorepos
和multirepos
之间的选择似乎不是什么大问题,但这是一个决定,将深刻影响您的公司的开发工作流程。至于它们的好处,我们可以列举一些:
随着monorepos的增长,我们在版本控制工具、构建系统和持续集成管道方面达到了设计极限。这些问题会让公司走multirepo
路线:
您可能已经注意到,大多数这些问题都是技术性的。在接下来的部分中,我们将了解那些坚持使用monorepos的公司是如何通过投资工具、添加集成和编写自定义解决方案来解决大多数问题的。
选择存储库策略不仅是一个技术问题,而且涉及到人们如何交流。正如康威定律所言,沟通对于打造伟大的产品至关重要:
任何设计系统的组织所产生的设计,其结构是该组织通信结构的复制品。 -梅尔文·e·康威
虽然multirepo允许每个团队独立管理他们的项目,但他们也设置了协作障碍。通过这种方式,他们可以充当眼罩,使开发人员只关注他们所拥有的部分,而忘记了整体情况。
另一方面,monorepo就像一个中心枢纽,一个市场广场,每个开发人员、工程师、测试人员和业务分析师都可以在这里会面和交谈。Monorepos鼓励对话,帮助我们消除隔阂。
Monorepo 已经存在很长时间了。三十年来,FreeBSD一直使用CVS以及后来的subversion monorepos进行开发和包分发。
许多开源项目已经成功地使用了monorepos。例如:
然而,真正的问题是商业软件是否能从monorepo布局中受益。考虑到这些优点和缺点,让我们来听听几家尝试过它们的公司的经验。
Airbnb最初的版本被称为“monorail”。它是一个完整的Ruby on Rails应用程序。当公司开始呈指数级增长时,代码库也紧随其后。当时,Airbnb推行了一项新颖的发布政策,称为民主发布,这意味着任何开发者都可以在任何时间发布产品。
随着Airbnb的扩张,民主程序的限制受到了考验。合并变化变得越来越难。Jens的团队实施了姑息性措施,如合并队列和增强监控。这些措施在一段时间内有所帮助,但从长远来看还不够。
Airbnb的工程师们为保住“monorail”进行了一场英勇的战斗,但最终,经过数周的争论,他们决定将该应用程序拆分为微服务。因此,他们创建了两个monorepos:一个用于前端,一个用于后端。两者都包含数百个服务、文档、用于部署的Terraform和Kubernetes资源以及所有维护工具。
当被问及monorepo布局的亮点时,他们说道:
“我们不想处理所有这些微服务之间的版本依赖性。使用monorepo,你可以在两个微服务之间通过一次提交进行更改[..]我们可以围绕单个存储库构建所有的工具。最大的卖点是你可以同时对多个微服务进行修改。我们运行一个脚本,然后检测monorepo中哪些应用程序受到了影响,然后部署这些应用程序。我们的主要好处是源代码控制。”
如果我们必须从所有这些故事中吸取一个教训,那就是正确的工具是有效的monorepos的关键——构建和测试需要重新考虑。我们可以使用智能构建系统来理解项目结构,并只对自上次提交以来发生变化的部分进行操作,而不是每次更新都重新构建完整的repo。
我们大多数人没有谷歌或Facebook那样的资源。我们该怎么办?幸运的是,许多大公司已经开放了他们的构建系统:
Monorepos得到了越来越多的关注,特别是在JavaScript中,如下面的项目所示:
源代码控制是monorepos的另一个痛点。这些工具可以帮助你扩展存储库:
Mercurial
:作为Git的替代品,Mercurial是一个分布式版本控制工具,它关注的是速度。Facebook使用Mercurial,并在过去几年里推出了许多加速补丁。Git CODEOWNERS
:允许您定义哪个团队拥有存储库中的子目录。当有人打开一个pull请求或推入一个受保护的分支时,代码所有者会自动被请求检查。GitHub和GitLab支持此功能。基于monorepo
故事的集合,我们可以定义一组最佳实践:
filter-branch
来处理大容量存储库。CODEOWERS
。Semaphore
)来大规模测试和部署应用程序。视情况而定。没有适合每个用例的直接答案。一些公司可能会选择monorepo一段时间,然后决定他们需要切换到 multirepos 或反之,而另一些公司可能会选择混合。如果有疑问,可以考虑一下,从 monorepo 到 multirepos 通常比反向更容易。但永远不要忘记,归根结底,这与技术无关,而是与工作文化和沟通有关。所以,根据你想要的工作方式来决定。