2. 领域驱动设计基础:DDD核心概念与战略设计
领域驱动设计(Domain-Driven Design,DDD)是一套应对复杂业务系统的建模与架构方法论。它强调以业务领域为核心,通过统一的语言和清晰的边界,将业务复杂性控制在模型内部。本章将系统梳理DDD的核心战术构件与战略设计思想,为后续GoBFF中的领域边界划分奠定理论基础。
2.1 核心战术构件
DDD的战术设计提供了四种基本建模元素:实体、值对象、聚合和领域服务。它们共同构成了领域模型的基本单元。
| 构件 | 定义 | 标识特征 | 典型示例 |
|---|---|---|---|
| 实体(Entity) | 具有唯一标识、生命周期和可变状态的对象 | 有ID,可被追踪和修改 | 用户、订单、商品 |
| 值对象(Value Object) | 通过属性值描述某个概念,无唯一标识 | 不可变,可替换,等值比较 | 地址、金额、颜色 |
| 聚合(Aggregate) | 一组相关对象的集群,由聚合根统一对外访问 | 有聚合根,内部一致性边界 | 订单(含订单项、支付信息) |
| 领域服务(Domain Service) | 无状态的操作,协调多个实体或值对象的业务逻辑 | 无状态,行为不属于单一实体 | 运费计算、库存校验 |
实践提示:在GoBFF架构中,实体和值对象通常定义在
internal/domain/ 包下,领域服务则放在 internal/domain/service/ 中。聚合根是事务一致性的最小单元,BFF层应尽量按聚合根粒度组织接口。
2.1.1 实体与值对象的抉择
区分实体与值对象是建模的第一步。核心判断标准是:该对象是否需要被追踪和修改?
- 实体:关注“是谁”,即使所有属性都相同,只要ID不同就是不同对象。例如:用户A和用户B即使姓名相同,也是两个不同的实体。
- 值对象:关注“是什么”,只要属性值相同就视为同一个对象。例如:地址“北京市朝阳区”无论出现在哪个订单中,都是同一个值。
避坑指南:初学者容易将“看起来有多个字段”的对象都建模为实体。实际上,优先使用值对象可以大幅降低模型复杂度。例如:电话号码、邮箱、坐标点等,都应设计为值对象。
2.1.2 聚合与聚合根
聚合是DDD中最重要的一致性边界。聚合根是聚合中唯一能被外部引用的对象,外部只能通过聚合根的方法来修改聚合内部的状态。
// 聚合根:Order
type Order struct {
ID string
Items []OrderItem // 值对象列表
Address Address // 值对象
Status OrderStatus // 值对象
}
// 外部只能通过 Order 的方法操作
func (o *Order) AddItem(item OrderItem) error {
if o.Status != OrderStatusPending {
return errors.New("只能向待支付订单添加商品")
}
o.Items = append(o.Items, item)
return nil
}
聚合设计原则:
- 聚合要小:一次事务只修改一个聚合。
- 聚合根全局唯一:通过全局ID引用,而非对象引用。
- 聚合内部强一致性:事务提交时,聚合内所有对象状态一致。
- 聚合之间最终一致性:跨聚合的修改通过领域事件异步协调。
2.2 DDD战略设计
战略设计关注的是大尺度上的领域划分,解决“如何将复杂业务拆解为可管理的子域”以及“子域之间如何协作”的问题。战略设计的核心产出是限界上下文(Bounded Context)和上下文映射图(Context Map)。
2.2.1 子域类型
战略设计的第一步是将整个业务领域划分为三种子域:
- 核心域(Core Domain):公司最核心的竞争力所在,需要投入最多资源自研。例如:电商平台的推荐算法、物流公司的路径规划。
- 支撑域(Supporting Subdomain):业务必需但非核心,通常定制化开发。例如:电商平台的商品管理、用户管理。
- 通用域(Generic Subdomain):行业通用能力,可直接采购或使用开源方案。例如:身份认证、短信通知、支付网关。
2.2.2 限界上下文
限界上下文是DDD中最关键的边界概念。每个限界上下文拥有:
- 独立的领域模型:同一个概念在不同上下文中可能有不同含义。例如:“用户”在订单上下文中是“收货人”,在客服上下文中是“投诉者”。
- 独立的数据库:每个上下文拥有自己的数据存储,避免直接访问其他上下文的表。
- 独立的团队:理想情况下,一个限界上下文由一个团队负责。
GoBFF映射:在GoBFF架构中,每个限界上下文通常对应一个独立的
internal/domain/ 包,BFF层通过 internal/bff/ 中的编排器(Orchestrator)来协调多个上下文的调用。上下文之间的通信优先使用领域事件或RPC接口,避免直接共享领域对象。
2.2.3 上下文映射关系
上下文映射图描述了限界上下文之间的协作模式。常见的映射关系包括:
| 关系类型 | 描述 | 适用场景 |
|---|---|---|
| 合作关系(Partnership) | 两个上下文协同完成一个流程,互相依赖 | 订单与支付上下文 |
| 共享内核(Shared Kernel) | 共享一小部分公共模型,但需严格同步 | 用户与权限上下文 |
| 客户-供应商(Customer-Supplier) | 上游提供接口,下游按需调用 | 订单上下文依赖库存上下文 |
| 防腐层(Anti-Corruption Layer) | 下游为保护自身模型,在上游接口外增加适配层 | 对接遗留系统或第三方服务 |
| 开放主机服务(Open Host Service) | 上游以协议方式公开服务,供多个下游使用 | 统一的支付网关服务 |
推荐实践:在GoBFF项目中,BFF层天然扮演了防腐层的角色。BFF将下游领域上下文的接口转换为前端友好的DTO,同时隔离了领域模型的变更对前端的影响。这是GoBFF架构的核心价值之一。
2.3 本章小结
DDD的战术构件(实体、值对象、聚合、领域服务)为微观建模提供了精确的工具,而战略设计(子域、限界上下文、上下文映射)则为宏观架构划定了清晰的边界。在GoBFF架构中,这两者缺一不可:
- 战术构件指导我们如何设计
internal/domain/中的领域模型。 - 战略设计指导我们如何划分微服务或模块边界,以及BFF层如何与各个领域上下文交互。