1. 领域驱动设计概述:DDD 核心概念、战略设计与战术设计、领域与子域、限界上下文

1.1 DDD 的起源与核心思想

领域驱动设计(Domain-Driven Design,DDD)由 Eric Evans 于 2003 年提出,其核心主张是:软件系统的复杂性与业务领域的复杂性成正比。DDD 并非一套技术框架,而是一套以业务领域为中心的建模与设计方法论,旨在让软件模型精确反映业务现实,从而降低长期维护成本。

核心信条: 代码即模型,模型即语言。开发团队与业务专家使用同一种语言(通用语言)进行沟通,并将这种语言直接映射到代码结构中。

1.2 战略设计与战术设计

DDD 将设计活动分为两个层次:战略设计 关注宏观边界与上下文关系,战术设计 关注微观模型元素的实现细节。两者缺一不可。

维度 战略设计 战术设计
关注点 系统边界、上下文映射、子域划分 实体、值对象、聚合、领域服务、仓储
产出物 限界上下文地图、上下文映射图 聚合根、领域事件、领域模型代码
适用阶段 项目启动、架构规划、多团队协作 具体模块开发、模型实现
典型问题 “订单系统与支付系统如何交互?” “订单聚合内应包含哪些实体?”
实践建议: 在 Go 项目中,战略设计决定了微服务拆分粒度与接口边界;战术设计决定了每个服务内部的包结构与模型定义。先做战略设计,再做战术设计,避免过早陷入实现细节。

1.3 领域与子域

业务领域(Domain)是组织所从事的业务范围。DDD 将一个大型领域拆分为多个子域(Subdomain),每个子域对应业务的一个核心能力或支撑能力。子域分为三类:

  • 核心子域(Core Domain): 系统最具竞争力的部分,需要投入最多资源精雕细琢。例如电商的订单履约、推荐引擎。
  • 支撑子域(Supporting Subdomain): 业务必需但非核心,通常可内部开发或外包。例如用户通知、权限校验。
  • 通用子域(Generic Subdomain): 行业通用能力,优先使用现成方案或开源组件。例如支付网关、短信发送、日志收集。
常见误区: 将“子域”等同于“微服务”。子域是业务概念,微服务是部署单元。一个子域可能拆成多个微服务,也可能多个子域合并为一个微服务。子域划分应以业务语义为准,而非技术便利。
领域与子域分层结构 核心子域(Core Domain) 订单履约 · 推荐引擎 · 定价策略 支撑子域(Supporting Subdomain) 用户通知 · 权限校验 · 数据导出 通用子域(Generic Subdomain) 支付网关 · 短信发送 · 日志收集 投入资源:核心子域 > 支撑子域 > 通用子域

1.4 限界上下文

限界上下文(Bounded Context) 是 DDD 中最重要的战略设计概念。它定义了一个模型生效的边界:在边界内部,模型术语、规则、数据格式保持严格一致;跨边界时,模型可以有不同的解释甚至不同的名称。

例如,“用户”在“订单上下文”中可能只包含用户 ID 和收货地址,而在“营销上下文”中则包含用户标签、积分等级和消费偏好。两个上下文中的“用户”是不同模型,通过上下文映射(Context Map) 进行转换。

1.5 上下文映射关系

限界上下文之间的协作关系通过上下文映射来描述。常见的映射模式包括:

映射模式 说明 适用场景
合作关系(Partnership) 两个上下文协同演进,一方变更需通知另一方 紧密耦合的核心子域之间
共享内核(Shared Kernel) 共享部分模型(如值对象、枚举)以减少重复 同一团队维护的多个上下文
客户-供应商(Customer-Supplier) 上游(供应商)决定模型,下游(客户)适配 平台层与业务层之间
防腐层(Anti-Corruption Layer) 下游主动建立转换层,隔离上游模型的污染 集成遗留系统或第三方服务
开放主机服务(Open Host Service) 上游以 API 形式暴露服务,下游通过 API 调用 微服务间的 REST/gRPC 通信
Go 实践提示: 在 Go 项目中,每个限界上下文通常对应一个独立的 go module 或包目录。上下文之间的通信优先使用接口(interface)而非直接依赖结构体,以便在测试时轻松替换为 mock 实现。
限界上下文与上下文映射示例 订单上下文 Order · OrderItem PaymentRecord ShippingAddress 支付上下文 Transaction · Refund PaymentMethod Settlement 营销上下文 Coupon · Campaign UserSegment PointsLedger 开放主机服务 防腐层 客户-供应商 每个限界上下文拥有独立的模型定义,跨上下文通过映射模式协作

1.6 通用语言

通用语言(Ubiquitous Language) 是 DDD 的基石。它要求团队(业务专家、产品经理、开发、测试)使用同一套术语进行沟通,并且这些术语必须直接体现在代码、文档、测试用例和数据库设计中。

  • 术语统一: 业务说“订单已支付”,代码中就是 Order.Status == Paid,而非 Order.Flag == 2。
  • 持续演进: 当业务规则变化时,通用语言随之调整,代码同步重构。
  • 避免翻译损耗: 不需要将业务语言“翻译”成技术语言,减少理解偏差。
Go 代码示例: 通用语言直接映射为 Go 的类型与常量命名。
// 通用语言:订单状态
type OrderStatus string

const (
    OrderStatusPending   OrderStatus = "pending"   // 待支付
    OrderStatusPaid      OrderStatus = "paid"      // 已支付
    OrderStatusShipped   OrderStatus = "shipped"   // 已发货
    OrderStatusDelivered OrderStatus = "delivered" // 已签收
    OrderStatusCancelled OrderStatus = "cancelled" // 已取消
)

// 通用语言:订单聚合根
type Order struct {
    ID        string      `json:"id"`
    Status    OrderStatus `json:"status"`
    Items     []OrderItem `json:"items"`
    Total     Money       `json:"total"`
}

1.7 本章小结

领域驱动设计为复杂业务系统提供了清晰的建模路径:

  • 通过战略设计划分领域与子域,识别核心能力;
  • 通过限界上下文划定模型边界,避免概念混淆;
  • 通过上下文映射定义跨边界协作规则;
  • 通过通用语言确保业务与代码的一致性。