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): 行业通用能力,优先使用现成方案或开源组件。例如支付网关、短信发送、日志收集。
常见误区: 将“子域”等同于“微服务”。子域是业务概念,微服务是部署单元。一个子域可能拆成多个微服务,也可能多个子域合并为一个微服务。子域划分应以业务语义为准,而非技术便利。
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 实现。
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 本章小结
领域驱动设计为复杂业务系统提供了清晰的建模路径:
- 通过战略设计划分领域与子域,识别核心能力;
- 通过限界上下文划定模型边界,避免概念混淆;
- 通过上下文映射定义跨边界协作规则;
- 通过通用语言确保业务与代码的一致性。