Go项目多模块结构如何设计_Go多module结构规范说明

Go多模块结构按业务边界、复用性、发布节奏和依赖隔离划分,每个go.mod对应独立构建、版本化、测试和发布的单元;核心原则包括提供稳定API、高频复用、独立发布周期、解耦编译部署或跨团队维护需求。

Go 多模块(multi-module)结构不是靠目录“看起来多”,而是按业务边界、复用性、发布节奏和依赖隔离来划分 module,每个 go.mod 对应一个可独立构建、版本化、测试和发布的单元。

模块划分的核心原则

一个 module 应该满足以下至少一条:

  • 对外提供稳定 API,被其他项目或模块频繁复用(如通用工具库、客户端 SDK)
  • 有独立的发布周期(比如 api 每周发版,worker 每月发版)
  • 需要与其他模块解耦编译或部署(例如 CLI 工具和后台服务共用部分逻辑,但不想强绑定)
  • 存在不同团队维护、不同权限控制或不同 CI/CD 流程的需求

典型目录结构示例(推荐)

以企业级后台服务为例:

myproject/
├── go.mod                     # 根 module,仅声明 proxy / replace,不写 require
├── cmd/
│   ├── api/
│   │   ├── main.go
│   │   └── go.mod             # api module:HTTP 服务入口,依赖 internal/api + internal/core
│   ├── worker/
│   │   ├── main.go
│   │   └── go.mod             # worker module:异步任务入口,依赖 internal/worker + internal/core
│   └── cli/
│       ├── main.go
│       └── go.mod             # cli module:命令行工具,轻量依赖 internal/core
├── internal/
│   ├── core/                  # 共享核心逻辑(domain/entity/usecase),无外部依赖
│   │   └── go.mod
│   ├── api/                   # HTTP 层专用逻辑(handler/middleware),依赖 core
│   │   └── go.mod
│   ├── worker/                # 任务调度/执行逻辑,依赖 core + third-party job queue
│   │   └── go.mod
│   └── storage/               # 数据访问层(repo/db/cache),可选单独 module
│       └── go.mod
├── pkg/                       # 可被外部引用的公共包(如 auth/jwt/logutil)
│   ├── jwt/
│   │   └── go.mod             # 独立 module,语义化版本,支持 go get
│   └── logutil/
│       └── go.mod
└── scripts/                   # 构建/发布脚本,不参与 go build

注意:根目录 go.mod 不写 require,只用于设置 GO111MODULE=on 环境下的代理或替换规则;各子 module 的 go.mod 自行管理依赖。

module 间依赖与版本管理

内部 module 之间用相对路径 replace 开发,发布时改用语义化版本:

  • 开发阶段,在 cmd/api/go.mod 中写:
    replace github.com/yourorg/myproject/internal/core => ../internal/core
  • 发布 pkg/jwt 后打 tag v1.2.0,其他 module 就用:
    require github.com/yourorg/myproject/pkg/jwt v1.2.0
  • 避免循环依赖:module A 不能直接 import module B,同时 B 又 import A;可通过提取公共 interface 到 corepkg 解耦

CI/CD 与构建建议

多 module 不等于每个 module 都要单独 CI:

  • cmd/ 下的服务类 module,建议独立构建镜像、独立部署
  • internal/ 下的 module,不单独发布,只在本地构建时被引用;CI 中可跳过测试或仅做单元测试
  • pkg/ 下的公共 module,应启用完整 CI(test + lint + version bump + push to proxy)
  • 使用 go list -m ./... 快速列出当前工作区所有 module,配合脚本批量操作

基本上就这些。多 module 结构不复杂,但容易忽略边界定义和 replace 管理,关键是让每个 go.mod 有明确的“谁用它、为什么独立、怎么升级”——而不是为了分而分。