主题
架构策略
项目架构策略
Monorepo
是一种项目开发与管理的策略模式,它代表"单一代码仓库(Monolithic Repository)
。在 Monorepo
模式中,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中,这些项目之间还可能会有依赖关系。
项目开发与管理模式
项目管理模式发展到现在,先后有三种项目管理模式的历史进程:
Monolithic(单体应用)开发模式
在软件开发的早期阶段,通常采用单体应用的开发模式。整个应用程序由一个单一的代码库、构建和部署流程组成。这种模式简单易懂,适合小型项目。
优点:
- 易于集成和部署。所有的代码在一个仓库里面,不需要特别的集中管理和协调,也可以直接在本地部署调试。
- 易于重用。所有的代码都在一个仓库中,开发人员开发的时候比较容易发现和重用已有的代码。
- 易于规范代码。所有的代码在一个仓库当中就可以标准化依赖管理,规范化代码的风格。
缺点:
- 代码维护性变差,随着功能以及代码量的大幅增加,代码功能耦合性增强。
- 构建时间过长,任何小修改必须重新构建整个项目,这个过程往往很长。
- 稳定性差,任意一个功能出现问题,可能导致整个应用挂掉。
Multirepo(多仓多模块)开发模式
为了解决单体应用的扩展性问题,团队开始将项目拆分为多个独立的仓库,每个仓库独立维护自己的代码和构建流程。这种模式更适合大型和复杂的项目,因为它提供了更好的隔离性和独立性,同时可以更灵活地管理多个团队的工作。
优点:
- 每一个项目都有一个独立的仓库,职责单一。
- 代码量和复杂性受控,项目由不同的团队独立维护、边界清晰。
- 单个项目也易于自治开发测试部署和扩展,不需要集中管理集中协调。
- 利于进行权限控制,可以针对单个仓库来分配权限,权限分配粒度比较细。
缺点:
- 代码和配置很难共享:每个仓库都需要做一些重复的工程化能力配置(如
eslint/test/ci
等)且无法统一维护,且不利于代码复用。 - 依赖的治理复杂:模块越来越多,涉及多模块同时改动的场景增加。如何保障底层组件升级后,其引用到的组件也能同步更新到位。这点很难做到,如果没及时升级,各工程的依赖版本不一致,往往会引发一些意想不到的问题。
- 开发人员缺乏对整个项目的整体认知:开发人员一般只关心自己的服务代码,看不到项目整体,造成缺乏对项目整体架构和业务目标整体性的理解。
- 存储和构建消耗增加:假如多个工程依赖
pkg-a
,那么每个工程下node_modules
都会重复安装pkg-a
,对本地磁盘内存和本地启动都是个很大的挑战。而且每个模块的发布都是相对独立的,当一次迭代修改较多模块时,总体发布时效就是每个发布流程的串联。对发布者来说是一个非常大的负担。 - 部署复杂化,每次部署需要一次性部署多个仓库,部署流程复杂,容易出错。
- 项目移交困难:当一个项目需要移交给其他团队时,需要将多个仓库移交给其他团队,移交过程复杂,容易遗漏出错,基本上需要重新梳理一遍。
Monorepo (单仓多模块)开发模式 框架内采用
现代主流模式
字节跳动、阿里、丁香园、Facebook、Google、Microsoft、Airbnb、Twitter、Uber、Netflix 等公司都在使用 Monorepo
模式进行开发。
回归单体管理:Monorepo
是一种试图回归单体管理优势的方法,但保留了多仓库开发的某些优点。它允许在一个代码库中管理多个项目、组件或服务,提供更好的代码共享和重用性。
现代工具支持:现代的版本控制系统和工具链使得 Monorepo
开发模式更为可行,例如像 Pnpm
、Yarn
、Lerna
和 Turborepo
等工具,它们提供了更好的管理、构建和部署多个项目的能力。
优点:
- 保留
multirepo
的主要优势 - 代码复用
- 模块独立管理
- 分工明确,业务场景独立
- 代码耦合度降低
- 管理所有项目的版本控制更加容易和一致,降低了不同项目之间的版本冲突。
- 可以统一项目的构建和部署流程,降低了配置和维护多个项目所需的工作量。
缺点:
Monorepo
可能随着时间推移变得庞大和复杂,导致构建时间增长和管理困难,git clone
、pull
的成本增加。- 权限管理问题:项目粒度的权限管理较为困难,容易产生非
owner
管理者的改动风险。
Monorepo + 微前端的架构
aPaas
平台的微应用适配其实就要求我们使用微前端,从兼容集团aPaas
平台的使用要求上,技术底座就要有微前端的能力。- 为项目添加应用级别的复用能力。假如一个项目使用了
A
、B
、C
三个应用去组合一个应用,其他项目也需要使用这三个应用或者其中的几个应用,那么我们可以将这些应用直接提取出来,作为其他项目可以直接内嵌这个应用,可以极大的提高复用能力 - 为持续升级做技术铺垫,抽离应用内所有的依赖和公共模块到其他模块内,可以让项目的升级更加的快速和简单。
- 只聚焦于业务开发,不用关心底层的兼容浏览器的转移、适配各个平台、编译器、ast抽象语法树、这类需要底层技术支持的功能,可以让业务开发者更加的专注于业务开发,不用关心底层的技术架构。