许多公司,如谷歌、微软和Airbnb等,已经长期实践了Monorepo架构。许多开源项目也已经成功地使用了Monorepo,如Babel、谷歌的Angular、Facebook的React、Vue等前端框架。如今,越来越多的小型团队也开始使用Monorepo。
在谷歌,几乎所有的代码都存在于一个大型的Monorepo中,几乎所有的工程师都能在其中查看几乎所有的代码。超过2万名工程师使用该Monorepo,包含超过20亿行代码。整个Monorepo中使用共享的构建系统、通用测试基础设施、代码浏览工具、代码审查工具,以及自定义源代码控制系统。尽管工程师可以查看和编辑几乎整个代码库,但所有的代码只有在得到代码所有者的批准后才能提交。代码所有权是基于路径的,目录所有者隐式地拥有所有子目录的所有权。
微软的Windows代码库存储在一个Monorepo中,拥有350多万个文件,大小超过270GB,这导致了使用Git来管理这样的项目变得困难。在这样的代码库上运行git checkout需要3h,git status需要10min,git clone需要12h。为了解决这个问题,微软开发了GVFS( Git Virtual File System )。通过这个系统,开发者在使用时会觉得所有文件都在本地,但实际上只有在文件第一次打开时才会进行下载。GVFS还积极管理Git在checkout和状态操作中需要考虑多少repo,因为任何未变化的文件都可以安全地被忽略。GVFS是在文件系统级别进行这些操作的,因此IDE和构建工具并不需要更改。使用GVFS管理庞大的代码库后,除了第一次构建比较慢之外,之后的git clone只需要几min,checkout只需要几十秒,status只需要几秒。
Airbnb最初的版本被称为“ the monorail ”,是一个完整的Ruby on Rails应用程序。当Airbnb的业务开始指数级增长时,代码库也随之增长。为了维护代码库的可维护性,Airbnb实施了一项名为“民主发布”的新颖发布政策。但随着业务的继续扩大,这项政策受到了挑战。最终,Airbnb的工程师们决定将应用程序拆分为微服务,并创建了两个Monorepo:一个用于前端,一个用于后端。这样做的优点是可以通过一次提交,在两个微服务之间进行更改,并且可以围绕一个存储库构建所有的工具。Airbnb的基础设施工程师Jens Vanderhaeghe表示:“我们不想处理所有这些微服务之间的版本依赖关系。使用Monorepo,您可以通过一次提交,在两个微服务之间进行更改。可以围绕一个存储库构建所有的工具。最大的卖点是,您可以同时对多个微服务进行更改。我们运行一个脚本,检测Monorepo中的哪些应用程序受到影响,然后部署这些应用程序。我们的主要好处是源代码控制。”
Uber使用Go语言编写大部分后端服务,并于2018年引入了Go Monorepo,发现构建效率立即提高。随着Go Monorepo的成熟,Uber将越来越多的项目转移到该仓库中,使用量迅速扩大。截止到2020年,Go Monorepo上有70000个文件,月提交数量达10000,活跃开发者900人。Uber的Go Monorepo可能是在Bazel上运行的最大的Go存储库之一。
Uber的前端项目经历了从Monorepo到Multirepo再到Monorepo的过程。项目最初采用Monorepo存储架构,但随着业务的发展,Monorepo出现了问题,如IDE阻塞、Git速度变慢、master崩溃等。当业务达到中等规模时,团队决定采用Multirepo架构,这解决了许多问题。然而,随着Uber业务的进一步发展,Multirepo架构开始显示出它的弱点,这不仅是关于技术问题,而且是更多关于开发者如何合作。管理数千个存储库的开销消耗了大量宝贵的时间,每个小组都有自己的编码风格、框架和测试实践,管理依赖关系也变得更加困难,最终很难将所有内容整合到一个产品中。最终,Uber的工程师们重新集结起来,决定再给Monorepo一次机会。