1. 领域驱动设计概述
1.1 DDD 核心概念
领域驱动设计(Domain-Driven Design,DDD)由 Eric Evans 于 2003 年提出,是一种以领域模型为核心的软件设计方法论。DDD 强调软件系统的复杂性与业务领域的复杂性直接相关,因此架构设计必须围绕业务领域展开,而非技术实现。
DDD 的核心概念可归纳为以下三层:
| 层级 | 核心概念 | 说明 |
|---|---|---|
| 领域层 | 实体(Entity)、值对象(Value Object)、聚合(Aggregate) | 表达业务逻辑与规则的核心模型 |
| 应用层 | 领域服务(Domain Service)、应用服务(Application Service) | 协调领域对象完成用例流程 |
| 基础设施层 | 仓储(Repository)、工厂(Factory)、事件(Event) | 提供持久化、消息、外部接口等技术支持 |
关键原则:领域模型是系统的“心脏”,技术实现(数据库、框架、消息队列)必须服从于领域模型的表达,而非反过来。
1.2 战略设计与战术设计
DDD 将设计过程分为两个层次:战略设计(Strategic Design)与战术设计(Tactical Design)。两者分别解决“如何划分边界”和“如何实现模型”的问题。
战略设计
- 限界上下文(Bounded Context):每个上下文拥有独立的领域模型和语言,避免概念混淆。
- 上下文映射(Context Map):描述不同上下文之间的协作关系(如防腐层、开放主机服务、共享内核等)。
- 通用语言(Ubiquitous Language):团队与业务专家使用同一套术语,贯穿代码、文档、讨论。
战术设计
- 实体:具有唯一标识、生命周期可追踪的对象。
- 值对象:无标识、不可变、描述性对象。
- 聚合:一组相关对象的集合,通过聚合根保证一致性。
- 领域事件:记录业务中发生的重要事实。
- 仓储:提供聚合的持久化与检索接口。
实践建议:在 Go 项目中,战略设计优先于战术设计。先通过事件风暴(Event Storming)或业务流程图识别限界上下文,再为每个上下文设计聚合与实体。
1.3 领域边界的重要性
领域边界是 DDD 战略设计的核心产出。没有清晰的边界,领域模型会退化为“贫血模型”或“大泥球”架构。边界的作用体现在以下方面:
- 语言隔离:不同上下文使用不同的通用语言,避免“用户”一词在订单上下文和客服上下文中含义冲突。
- 模型独立:每个上下文内的模型可以独立演进,不受外部变化影响。
- 团队自治:大型项目中,每个限界上下文可由独立团队负责,降低沟通成本。
- 技术解耦:边界内可以选择最适合的技术栈(如不同数据库、消息队列)。
常见误区:将微服务数量等同于限界上下文数量。实际上,一个限界上下文可以包含多个微服务,也可以只包含一个模块。边界是逻辑概念,微服务是部署单元。
1.4 限界上下文与领域边界的映射关系
限界上下文是领域边界的具体表现形式。在 Go 项目中,一个限界上下文通常对应一个独立的 Go Module 或 Package。以下表格展示了不同规模项目中的边界映射策略:
| 项目规模 | 限界上下文数量 | Go 组织方式 | 典型示例 |
|---|---|---|---|
| 小型(1-3 人) | 2-4 个 | 单个仓库内多 package | 订单上下文、支付上下文 |
| 中型(4-10 人) | 4-8 个 | 多 Module 单仓库 | 用户上下文、商品上下文、库存上下文 |
| 大型(10+ 人) | 8-20 个 | 多仓库多 Module | 每个上下文独立 Git 仓库 |
Go 实践提示:使用
go.work 文件管理多 Module 项目,可以在开发阶段保持本地依赖的灵活性,同时保持发布时的独立版本控制。
1.5 本章小结
- DDD 的核心在于领域模型,而非技术实现。
- 战略设计关注边界划分,战术设计关注模型实现。
- 领域边界通过限界上下文表达,在 Go 中映射为独立的 Module 或 Package。
- 清晰的边界带来语言统一、模型独立、团队自治、技术解耦四大收益。