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)。

DDD战略设计核心概念关系图 核心域 核心竞争力 最复杂、最投入 支撑域 业务必需但非核心 可外包或采购 通用域 行业通用能力 认证、支付、通知 限界上下文 A 订单上下文 限界上下文 B 库存上下文 限界上下文 C 支付上下文 上下文映射关系 虚线箭头表示“下游依赖上游”,每个限界上下文拥有独立的领域模型和数据库

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层如何与各个领域上下文交互。