单一仓库或多仓库策略

除了团队规模和节奏,代码结构的方式也会对架构产生影响,如果你想执行逆向Conway法则的话。有两种策略:

  • 单一仓库策略(Mono-repo strategy):只有一个仓库,包含应用程序所需的所有模块(或微服务)。

  • 多仓库策略(Multi-repo strategy):每个模块或微服务都有自己的仓库,并且你必须部署多个仓库才能让整个应用程序正常工作。

这两种策略都有优缺点。单一仓库策略的最大优势是,部署和调试整个应用程序非常简单。但单一仓库往往会很快变得非常庞大,这会降低Git的性能。而且,随着仓库的增长,独立部署和测试应用程序的不同部分变得更加困难。这导致架构的耦合性更强。

使用大型单一仓库

在Git的上下文中,大仓库指的是包含大量文件和历史记录的仓库,这些仓库的大小会显著影响Git操作的速度和性能。例如,Linux内核的仓库大约有3GB,克隆和使用Git命令的速度虽然较慢,但仍在可接受范围内。然而,Windows仓库大约有300GB,大小是Linux内核的100倍,执行某些Git操作时需要较长时间:

  • git clone:大约需要12小时

  • git checkout:大约需要3小时

  • git status:大约需要8分钟

  • git add 和 git commit:大约需要3分钟

  • git clone:从12小时减少到90秒

  • git checkout:从3小时减少到30秒

  • git status:从8分钟减少到3秒

许多这些优化已经成为标准Git客户端的一部分。例如,你可以使用 git sparse-checkout([https://git-scm.com/docs/git-sparse-checkout](https://git-scm.com/docs/git-sparse-checkout)),允许你只下载仓库中你需要的部分。

如果你的仓库真的非常大,可能需要使用微软的定制版本;否则,通常可以通过正常的Git功能进行优化。

使用主题和星标列表组织您的仓库

多仓库策略的最大优势在于,它减少了单个仓库的复杂性。每个仓库都可以独立维护和部署。最大的劣势是,很难构建和测试整个应用程序。要从真实用户那里获取反馈或调试复杂的错误,通常仅仅部署单个服务或模块是不够的——你需要更新整个应用程序。这意味着需要在你的仓库边界之间协调多个部署。

如果你选择多仓库策略,你将会有许多小仓库。良好的命名约定可以帮助你对它们进行结构化。你还可以使用主题来组织你的仓库。主题可以在仓库的右上角设置(见图17.9)。

image 2024 12 27 17 48 45 618
Figure 1. 图17.9 - 你可以为仓库设置主题以便更好地发现

你可以使用 topic: 关键词来过滤你的仓库(见图17.10):

image 2024 12 27 17 49 01 357
Figure 2. 图17.10 - 基于主题过滤仓库

另一个可以帮助你组织大量仓库的功能是收藏列表。这是一个个人功能,不能共享。在你的GitHub个人资料中,你可以创建列表并组织你的收藏仓库(见图17.11):

image 2024 12 27 17 49 17 905
Figure 3. 图17.11 - 在列表中组织你的收藏仓库

你可以像浏览器中的收藏夹一样使用这些功能,但它们并不能解决部署、调试或测试整个应用程序的问题。

如果你使用的是Kubernetes来管理微服务,你可以在Visual Studio Code中使用Bridge to Kubernetes插件([https://marketplace.visualstudio.com/items?itemName=mindaro.mindaro](https://marketplace.visualstudio.com/items?itemName=mindaro.mindaro))来在生产或测试集群的上下文中调试本地服务(见Medina A. M., 2021)。但是,如果你依赖一次性构建和部署所有服务,最佳的解决方案是拥有一个元仓库,将所有服务作为子模块引用。

使用 Git 子模块结构化您的代码

你可以使用一个元仓库,包含所有其他仓库作为子模块。这使得你可以通过一个命令克隆所有仓库:

$ git clone --recurse-submodules

或者,如果你已经克隆了元仓库,并且想要更新它,可以使用以下命令:

$ git submodule update --init --recursive

该仓库可以包含部署整个应用程序的脚本或工作流。你可以使用这个元仓库进行发布管理,并将稳定的版本捆绑在一起。如果你使用分支来管理发布版本,那么可以将你的子模块设置为某个特定分支,并在发布最新版本之前更新它:

$ git config -f .gitmodules submodule.<SUB>.branch main
$ git submodule update --remote

如果你使用标签来管理发布版本,那么可以将每个子模块设置为特定版本并提交到你的元仓库:

$ cd <SUB>
$ git checkout <TAG>
$ cd ..
$ git add <SUB>
$ git commit -m "Update <SUB> to <TAG>"
$ git push

其他人可以拉取更改并更新子模块到与标签相对应的版本:

$ git pull
$ git submodule update --init --recursive

Git子模块是处理多仓库并独立部署的一个很好的方式,同时仍然能够将整个应用程序进行管理。但是请注意,你的子模块之间的依赖关系越多,维护元仓库并保持它们处于可部署状态的复杂度就越高。

什么是正确的策略?

无论是单一仓库(mono-repo)策略还是多仓库(multi-repo)策略,更适合你的团队,这都与第16章《松耦合架构与微服务》中我们讨论的演化设计密切相关。单一仓库适用于小型产品和全新项目。随着规模和复杂度的增加,最好将微服务或模块拆分并移到各自的仓库中。但始终要考虑可测试性和可部署性——无论是对单个服务/模块,还是对整个应用程序。