Go 的 DDD 工程化项目实践


Go 通用项目结构

关于 Go 项目的目录结构如何设计这一问题?Go 官方其实并没有定义标准的项目结构分层,但社区维护了一个 project-layout 仓库,其中包含了一个通用的项目结构示例,大家在实践中基本会遵循这个规范。
下面是一个通用的项目结构示例,并且可能因项目的规模、需求和偏好而有所不同。

project/
├── api/
│   ├── handler/         # API请求处理程序
│   ├── middleware/      # API中间件
│   └── router.go        # 路由定义
├── cmd/
│   ├── app/             # 应用程序入口点
│   └── cli/             # 命令行接口入口点
├── config/              # 配置文件和配置相关代码
├── internal/            # 私有应用程序和库代码
│   ├── model/           # 数据库模型
│   ├── repository/      # 数据库访问层
│   ├── service/         # 业务逻辑层
│   └── util/            # 工具函数
├── migrations/          # 数据库迁移文件
├── pkg/                 # 可公共使用的库代码
├── scripts/             # 构建、安装等脚本
├── test/                # 测试相关代码
├── web/                 # Web前端相关代码
├── .gitignore           # Git忽略文件列表
├── LICENSE              # 项目许可证
├── README.md            # 项目说明文件
└── go.mod               # Go模块定义文件

MVC传统架构

经典模型

┌───────────────┐       ┌────────────┐       ┌──────────────┐  
│  Controller   │◄─────►│  Service   │◄─────►│  Repository  │  
└───────────────┘       └────────────┘       └──────────────┘  
  (view layer)       (controller layer)    (model layer)  

目录结构

Controller + VO / Service + BO / Repository + entity

server
.
├── cmd                 # 执行目录
├── common              # 通用包
├── configs             # 配置参数变量
├── database            # 数据库连接
├── go.mod
├── internal
│   ├── controller      # 接口层
│   │   └── vo          # VO(View Object)模型
│   ├── repository      # 访问持久化层
│   │   └── entity      # Entity 实体
│   ├── pkg             # 内部库
│   └── service         # 业务逻辑层
│       └── bo          # BO(Business Object)模型
├── main.go             # 主入口
├── pkg                 # 外部库
├── router              # 路由系统
└── test                # 测试目录

对于传统面向过程的贫血模型而言,MVC 架构更加注重业务逻辑的封装和处理。在这种模型中,重点是强调 Service 层的职责,而对于 BO(Business Object)层则相对较轻。

DDD架构

经典模型

目录结构

server
├── README.md               # 项目文档
├── application             # 业务调度层
│   ├── event               # 微服务事件推送或订阅
│   │   ├── publish         # 事件发布
│   │   └── subscribe       # 事件订阅
│   └── service             # 用于连接 Controller 和 Domain,进行三方接口调用等其他操作
├── domain                  # 领域服务层(领域逻辑和领域对象,主要的业务逻辑,采用充血模型)
│   ├── aggregate01         # Aggregate 聚合根目录
│   │   ├── entity          # entity 实体、VO 值对象以及工厂模式(Factory)相关
│   │   ├── event           # 事件实体以及与事件活动相关的业务逻辑代码
│   │   ├── repository      # 持久化领域对象,通常仅包括仓储接口,仓储实现应放到基础架构层实现
│   │   └── service         # 领域服务代码,一个领域服务是多个实体组合出来的一段业务逻辑
│   ├── aggregate02
│   └── ...
├── go.mod                  # 依赖文件
├── infrastructure          # 基础设施层
│   ├── api                 # 第三方 API/SDK
│   ├── configs             # 配置参数变量
│   ├── database            # 初始化数据库
│   ├── mq                  # 消息队列连接和配置
│   ├── persistence         # 数据持久化(Domain 层 repository 的具体实现,数据库 CRUD 操作) 
│   └── pkg                 # 工具函数
│       ├── common          # 与业务相关包
│       └── utils           # 公共基础包
├── interfaces              # 接口层
│   ├── assembler           # 实现 DTO 数据传输对象与 Domain Entity 之间的相互转换和数据交换,从表示层(Presentation Layer)向领域层(Domain Layer)进行数据传递
│   ├── controller          # 控制器路由函数
│   └── dto/vo              # 可包含多个领域对象的属性:DTO(Data Transfer Object)主要关注数据的传输,通常用于面向服务或接口设计,用于在系统的不同部分之间传递数据。VO(View Object)则更常用于用户界面 UI 层,用于呈现数据给用户
└── main.go                 # 主入口

在 DDD (领域驱动设计) 中,需要将重点放在领域层(Domain Layer)进行业务逻辑和规则的实现。服务层(Service Layer)主要负责协调和调度各个领域对象之间的交互。

简单来说,对于面向对象充血模型的 DDD 而言,是重 Domain 轻 Service!

架构图

基本概念

在 DDD 的世界中,涉及到了很多概念,包括但不限于以下内容:

  • 统一语言
  • 限界上下文
  • 领域、子域、支撑域
  • 聚合、实体、值对象
  • 接口层、应用层、领域层、基础设施层
  • 贫血模型、充血模型

总结

本文主要介绍了go项目一般目录结构、MVC目录结构、DDD目录结构,每种架构都有使用场景,作为开发者,需要深入理解各个架构的优缺点,根据自身项目规模、复杂度选择合适的架构。

参考

[1]Go 的 DDD 工程化项目实践



文章作者: Alex
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alex !
  目录