Monorepo是一个新的名词,但不是一个新的概念。从软件开发最开始,我们已经在开始用这种模式了。这种模式的一个中心思想就是,用一个repo来管理所有的源代码。除了这种模式以外,另一个比较受推崇的模式就是multirepo,也就是用多个repo来管理自己的源代码。
不需要深刻思考这两种模式,各有利弊。今天我们来分别说一下这两种模式,但会着重来讲使用Monorepo可能会遇到的问题。
现在比较大型的软件开发公司,比如说Google, Uber, Netflix他们都在使用monorepo。但是对于我们中小型公司或者个人开发者来说,到底需不需要用monorepo,还是选择multirepo?
好,我们就现在具体谈一下monorepo。在这种模式下,你所有的设计文档,所有的源代码,所有的所有都放在一个repo里面。这样做的好处有这些:
你的一次提交可以解决所有的问题。
这个提交可以是添加一个功能,修改一个bug,这个功能添加或者代码修改会涉及很多不同的模块儿,这些模块都可以在一个change request里面做完。
因为所有的这些修改都在一个repo里面,这样你查找历史,查看这些修改之间的关联都比较容易。
当然了,这个好处的获取需要所有的程序员和文档提交者都遵循一个统一的格式。
另一个好处,是所有的人都有访问权限。这样就杜绝了权限申请方面的种种问题。不存在这些代码,某些人看不了的问题。整个开发团队里面没有任何秘密。
好,上面说了monorepo的好处, 那为什么现在很多人都在用multirepo呢?
现在就来说说monorepo的坏处。
Monorepo, 一个最大的问题就是随着程序规模的不断增加,代码量的增加,文档的增加,整个repo会变得越来越大。
我以前做过一个Nike的项目, 那个项目使用的就是monorepo的模式。那个repo当时的大小是21g。怎么样?你的小心肝还能承受得住吧?
试想一下,一个程序员只想改一下其中的一个翻译文字,你就需要把这21G大小的整个repo都拿到你的本地来。这个过程一定是欲仙欲死的。现在使用multirepo的人一定会对你说good luck。
另一个坏处也是上面说的好处,就是权限访问的问题。Monorepo模式下的权限是开放的。代码安全,文档安全,都会是一个需要好好考虑的问题。
这个方面如果处理不好的话,对整个团队整个项目带来的后果可能是灾难性的。
像google这样的大公司他们都用自己的代码管理系统,那一个程序员要修改一个模块的代码的时候,他需要把所有的项目代码都下载到本地来,并获取最新的代码。做一个修改以后,check in完成就会进行整个项目的编译。整个项目可能需要两个小时的编译时间,这个时候,这个程序员可以跟别人聊聊天,可以学点东西,这也是很好的一种程序员生活。在monorepo的开发模式下,这是一个非常常见的工作状态。
为了对这些修改做好标志,每一次一些标志性的修改都会添加一个版本号。对应一个版本号都会有一个版本历史。对应每个版本号又会有一个对应的标签。大部分时间我们只对最新的版本感兴趣。
接下来我们来看一下multirepo, 在这种模式下,你很少见到一个非常庞大的代码库或者文档库。但这不能说这种模式,就是完美的。它还会有别的其他的问题。
这种模式的总的设计是一个把一个大的问题分成几个小的问题来解决。通过问题的细化,减少整个问题解决的复杂度,从而让自己的工作更加顺手,更加有保障。
上面这个设计是不是听起来很熟悉,对了, 它跟微服务架构是一个理念。
通过这个分解,每一个小部分作为一个单独的repo。每个repo,可以分给不同的小组来开发和管理。每个小组只需要关心这一小部分工作就可以了。每一个小的部分都可以单独的进行买酒测试和开发。这个是好的一个方面。
下面来说一个坏的方面。因为每个小组可以各自为战。这样就给协同工作带来很大的问题。比如说一个小组的模块进行了升级,导致现有的大系统其他模块儿无法正常工作。这种现象在微服务架构系统的开发中非常常见。
如果把这个坏的方面再发挥到极致,就是每个组件之间互相依赖互相破坏,这样子你整体系统可能就陷入万劫不复的深渊。也就是说,随着微服务架构,继续把模块儿进细化,每个模块失去了紧密的联系,与此同时又没有很好的管理机制把握全局, 导致整个项目开发失去了控制,这也是很多微服务架构系统失败的原因。
所以在multirepo的开发过程中,非常重要的一点就是避免过度的细分。一定要有一个机制来把握全局,时刻监控整个开发环境是否正常。
制定标准是一个很有意思的话题, 虽然说技术上很难争高下, 但是总会辩论出一个最好的方案来,但是最严重的有时候根本不是技术上的问题。这个里面就会有很多说不清道不明的问题了。
就因为如此,在一些大公司当中,因为人员的素质都比较高,都是高手,常言说一山不容二虎,这里山中有好几只,几十只老虎。在这种情况下,用一只老虎的标准来把握全局是很难的。
所以宁愿牺牲一些下载时间,编译时间上的代价,最终他们还是继续使用monorepo的模式。
还有一个在multirepo中不可忽视的一个问题就是为了保证一个功能的完整运行, 即使再小的改动,也有可能对所有的repo进行更新。这是一个非常烦人的过程。
我工作过的一个multirepo项目,它里面有20多个模块。要想使整个系统工作完整,你需要把这20多个模块都下载到本地来,当然,你可以采用一些比较简洁的方式,比如说docker container的image, 尽可能的减少与过多的模块儿直接的接触。在这种模式模式下我相信你是非常喜欢黑盒模式的。因为模块太多,你根本不想搞清楚它里面到底在干什么。只要能给你工作就行了。一个是太烦人,另外一个是时间太紧张了。
那么现在的问题就是,上面两种模式哪种更好呢?我的观点是,不管你喜欢哪种模式,选择哪种模式,他们都是你的工具,你要控制他们,而不是他们控制你。
这种模式的本意都是想让你的工作做得更好。
Monorepo你需要做的是尽可能的把你的测试案例细分开。这样你在提交一个修改的时候,就不需要把所有的测试都过一遍,那样太费时间了。
Multirepo对于你自身模块的测试案例,你需要做的是把与你的模块相关的测试案例都放进来。在你提交一个修改的时候,要保证所有的这些案特殊案例都通过。如果需要下载相关模块的修改更新,要尽快通知大家去下载。
一个很常用的模式是这两种模式的结合。你比如说一个修改,你可能需要修改很多个repo, 那你可以考虑把这多个repo合成一个。
这个话题还有很多要可以谈的,我们这一期就先谈这些吧。