"分"与"合"的哲学碰撞,Monorepo vs Multirepo

2,942 阅读6分钟

本篇为大家梳理分别基于“分”“合”两种哲学思想的MultirepoMonorepo代码管理方式

Multirepo

Multirepo(one-repository-per-module)相对较为传统,顾名思义这种方式提倡把项目按模块分为多个代码库,通过科学的分解,可是实现每个repo独立开发和测试从而提升开发效率

在Multirepo的开发过程中,非常重要的一点就是避免过度的细分。一定要有一个机制来把握全局,时刻监控整个开发环境是否正常

Multirepo的优势

  • 灵活

每个repo可以灵活选择开发工具和环境配置等

  • 安全

自然的权限控制,发布上线对其他项目无影响

Multirepo的劣势

从管理形态上我们也很容易看出,这种代码管理方式存在如下缺点:

  • 代码复用

在多个repo间涉及公共组件、公共函数或公共配置(如各种config)时候,代码复用就成了问题。你可能想过如下解决方案:

  • copy相关代码到目标目录? -- 维护成本过高

  • 抽取公共逻辑发npm包? -- 修改->发布->安装成本高

  • 版本管理

在 MultiRepo 的开发方式下,依赖包的版本管理有时候是一个特别玄学的问题。比如说刚开始一个工具包版本是 v1.0.0,有诸多项目都依赖于这个工具包,但在某个时刻,这个工具包发了一个break change版本,和原来版本的 API 完全不兼容。而事实上有些项目并没有升级这个依赖,导致一些莫名的报错

当项目多了之后,很容易出现这种依赖更新不及时的情况。这又是一个痛点

  • 开发调试

涉及多个项目开发时,你可能需要开启多个IDE窗口进行切换开发,另外虽然可以使用npm link方式进行调试,但手动管理诸多link操作十分不便

  • 项目基建

由于在 MultiRepo 当中,各个项目的工作流是割裂的,因此每个项目需要单独配置开发环境、配置 CI 流程、配置部署发布流程等等,甚至每个项目都有自己单独的一套脚手架工具,然而很多情况下这些项目里的基建和逻辑是有很大部分重复的,而且各个项目间存在构建、部署和发布的规范不能统一的情况下维护成本也高了起来。

monorepo

Monorepo的思想是严格统一,多个项目放在一个仓库里面。比较知名的像Vue3、babel、npm7都是在用Monorepo方式进行管理的。Monorepo常见目录结构如下:

- packages
  - project1
    - src
      - index.ts
    - package.json
  - project2
    - src
      - index.ts
    - package.json
  - project3
    - src
      - index.ts
    - package.json
- lerna.json
- package.json
- tsconfig.json

image.png

优势

  • 统一工作流

首先是 工作流的一致性 ,由于所有的项目放在一个仓库当中,复用起来非常方便,如果有依赖的代码变动,那么用到这个依赖的项目当中会立马感知到。并且所有的项目都是使用最新的代码,不会产生其它项目版本更新不及时的情况,对开发调试而言都带来了方便

  • 降低基建成本

其次是 项目基建成本的降低 ,所有项目复用一套标准的工具和规范,无需切换开发环境,如果有新的项目接入,也可以直接复用已有的基建流程,比如 CI 流程、构建和发布流程。这样只需要很少的人来维护所有项目的基建,维护成本也大大减低

  • 提升团队协作效率

再者, 团队协作也更加容易 ,一方面大家都在一个仓库开发,能够方便地共享和复用代码,方便检索项目源码,另一方面,git commit 的历史记录也支持以功能为单位进行提交,之前对于某个功能的提交,需要改好几个仓库,提交多个 commit,现在只需要提交一次,简化了 commit 记录,方便协作

劣势

Monorepo的缺点也显而易见

体积问题

因为所有code都在一个repo下,这就导致了随着项目越来越复杂,整个repo的体积会变得很大。据说某大公司员工想要修改项目中的某个小样式,需要将数以十G的repo拉到本地,听起来确实是个噩梦

当然对此问题也可借助git本身提供的一些机制进行优化,有兴趣的可以了解下稀疏检出浅克隆

权限问题

Monorepo模式下的权限是开放的。代码安全,文档安全,都会是一个需要好好考虑的问题。这个方面如果处理不好的话,对整个团队整个项目带来的后果可能是灾难性的

版本控制

仓库变得太大,对版本控制技术会有很大的挑战。因为 Git 社区建议的是使用更多更小的代码库,Git 本身并不适合单个巨大的代码库

总结

Monorepo和Multirepo都是管理组织代码的方式,这两者的核心区别可以归结为你相信怎样的哲学能让团队在一起工作的效率最高(多元化 vs 集中管理),那么现在的问题就是,上面两种模式哪种更好呢?还是那句话“存在即合理”,工具都是用来服务生产的,能更有效解决当下问题的,就是更好的

后记

在实际场景来落地 Monorepo,需要一套完整的工程体系来进行支撑,因为基于 Monorepo 的项目管理,绝不是仅仅代码放到一起就可以的,还需要考虑项目间依赖分析依赖安装构建流程测试流程CI发布流程等诸多工程环节,同时还要考虑项目规模到达一定程度后的性能问题,比如项目构建/测试时间过长需要进行增量构建/测试按需执行CI等等 ,在实现全面工程化能力的同时,也需要兼顾到性能问题

因此,要想从零开始定制一套完善的 Monorepo 的工程化工具,是一件难度很高的事情。不过社区已经提供了一些比较成熟的方案,我们可以拿来进行定制,或者对于一些上层的方案直接拿来使用。

其中比较底层的方案比如 lerna,封装了 Monorepo 中的依赖安装脚本批量执行等等基本的功能,但没有一套构建、测试、部署的工具链,整体 Monorepo 功能比较弱,但要用到业务项目当中,往往需要基于它进行顶层能力的封装,提供全面工程能力的支撑。

当然也有一些集成的 Monorepo 方案,比如 nxrushstack,提供从初始化、开发、构建、测试到部署的全流程能力,有一套比较完整的 Monorepo 基础设施,适合直接拿来进行业务项目的开发。不过由于这些顶层方案内部各种流程和工具链都已经非常完善了,如果要基于这些方案来定制,适配和维护的成本过高,基本是不可行的

参考文章