编程 把多个服务塞进一个 repo:12-Factor 基准代码原则在真实项目里的边界

2026-09-11 00:04:16

把多个服务塞进一个 repo:12-Factor 基准代码原则在真实项目里的边界

订单、支付、通知三个服务最早放在同一个仓库里。为了省掉一次 HTTP 调用,通知服务直接 import 了订单模块的内部 service 包。当时的收益是少写一个客户端、少维护一份 DTO。半年后想给通知单独扩容时发现:构建产物里带着订单的整条依赖树;改一个订单内部函数签名会同时编译失败三个服务;打 tag 时也说不清这个 tag 属于谁。

原则:一份基准代码,多份部署

12-Factor 应用用版本控制系统管理,Git、Mercurial、Subversion 都算。一份用来跟踪代码所有修订版本的数据库被称作代码库(code repository, code repo, repo)。

在 SVN 这类集中式系统里,基准代码指控制系统中的这一份代码库;在 Git 这类分布式系统里,基准代码指最上游的那份代码库。

基准代码和应用之间保持一一对应:

  • 一旦有多个基准代码,就不能称为一个应用,而是一个分布式系统。分布式系统中的每一个组件都是一个应用,每个应用可以分别使用 12-Factor 开发。
  • 多个应用共享一份基准代码有悖于 12-Factor 原则。解决方案是把共享代码拆成独立的类库,用依赖管理策略加载。

每个应用只对应一份基准代码,但可以同时存在多份部署。生产环境、一个或多个预发布环境、每个开发者本机的实例,都各算一份部署。所有部署的基准代码相同,版本可以不同——开发者的提交没同步到预发布,预发布的提交没同步到生产,它们仍是同一个应用的不同部署。

来源:https://12factor.net/zh_cn/codebase (The Twelve-Factor App,Adam Wiggins)

monorepo 本身不违规,违规的是没有部署边界

一个 repo 装一个应用、附带构建脚本和文档,这不违反原则。违反的是把多个可以独立部署的应用塞进同一份基准代码,并让它们互相引用内部实现。

判断依据不复杂:这个单元能不能单独打 tag、单独构建、单独回滚。如果做不到,那它名义上是一个 repo,实际是一个分布式系统被压在了一个 codebase 里。

共享能力的正确出口是拆成独立依赖,按语义化版本发布,走内部制品库:

// package.json
"dependencies": {
"@corp/order-sdk": "^2.3.1"
}

com.corp
order-sdk

2.3.1

// go.mod
require github.com/corp/order-sdk v2.3.1

复制粘贴共享代码的问题是版本漂移:一个 bug 要改 N 处,改完还不确定哪几个服务跟上了。直接 import 同仓库另一个应用的内部实现,问题更隐蔽——编译期看不出耦合,等到要拆服务、要单独发布时才暴露。内部库的代价是要维护发布流程和版本升级,但这个代价换的是每个应用能独立演进。

用 tag / commit 作为部署触发点

一份代码库、多份部署,意味着部署动作必须能定位到具体的版本:

git tag -a v2.3.1 -m "release 2.3.1"
git push origin v2.3.1

GitLab CI 用 CI_COMMIT_TAG 判断当前流水线是否由 tag 触发:

deploy:
stage: deploy
script:
- ./deploy.sh
rules:
- if: '$CI_COMMIT_TAG'

GitHub Actions 直接监听 tag push:

on:
push:
tags:
- 'v*'

几个容易踩的点:

  • tag 可以被强推覆盖(git push -f origin v2.3.1),要审计就记录 tag 指向的 commit SHA,而不是只记 tag 名。
  • CI_COMMIT_TAG 只在 tag 流水线里有值,分支流水线中是空字符串,脚本里判空,否则 deploy.sh 会拿到空版本号。
  • 同一份代码库对应多份部署,环境差异应该走参数或配置,不要写进 tag 名,否则预发布和生产会各自漂出一套 tag 规则。
  • 如果 repo 里确实有多个应用,tag 加前缀区分:order-v2.3.1notify-v1.4.0,否则 CI 无法判断该部署哪一个。

边界

真正难切的是那种「只共享几个常量或协议定义」的场景。为几十行代码单开一个库,版本升级成本可能高于收益;留在原仓库又会让边界变模糊。这条线在哪,取决于团队规模和发布频率,没有通用答案。

复制全文 生成海报 Code Base 12-Factor 代码库 Monorepo CI CD

推荐文章

程序员茄子在线接单