《DDD 入门:让代码说业务语言》

92 阅读3分钟

当系统越来越复杂,你会发现:

  • Service 方法越来越多,逻辑交叉混乱
  • 数据表和业务逻辑绑在一起,改动一次牵一发动全身
  • 开发、测试、业务沟通成本越来越高

这时候,仅靠 CRUD 或传统分层架构已经无法支撑业务增长。
DDD(Domain-Driven Design,领域驱动设计)正是为解决这种复杂业务而生的一套方法论。


第一部分:DDD 的核心思想

DDD 的核心目标:

让软件的结构与业务逻辑保持一致,让开发人员和业务人员讲同一套语言。

核心理念包括:

  1. 领域(Domain)

    • 系统要处理的业务范围。
    • 示例:在资产管理系统中,领域可以是“资产管理”、“策略匹配”、“告警通知”。
  2. 限界上下文(Bounded Context)

    • 每个上下文内部术语、模型一致,但上下文之间可以重复定义同一概念。
    • 示例:资产管理上下文中的“资产”,与用户管理上下文中的“资产”可能含义不同。
  3. 统一语言(Ubiquitous Language)

    • 团队(开发 + 测试 + 业务)使用统一的语言描述业务。
    • 示例:所有文档、代码、接口中,“资产策略匹配”都用同一术语。

第二部分:DDD 的战术模式

DDD 不只是概念,还提供具体建模手段:

模式作用示例
实体(Entity)有唯一标识的业务对象资产、订单、用户
值对象(Value Object)没有唯一标识,按属性值判断相等金额、坐标、端口信息
聚合(Aggregate)事务一致性边界,聚合内部保证规则订单聚合 = 订单 + 订单明细
聚合根(Aggregate Root)聚合的唯一入口,外部只能通过它操作聚合订单根对象控制订单明细的增删改
领域服务(Domain Service)无法归属实体的业务逻辑资产策略匹配、支付计算
仓储(Repository)持久化聚合对象AssetRepository、OrderRepository
领域事件(Domain Event)聚合内部状态变化,可被外部订阅订单支付成功事件 → 触发库存扣减

第三部分:DDD 的落地原则

  1. 聚焦核心业务

    • 不必为 CRUD 小功能使用 DDD。
    • 优先为核心领域建模,让业务逻辑清晰可演化。
  2. 分层清晰

    ┌───────────── Interface ─────────────┐
    │ Controller / API                     │
    └─────────────▲─────────────┘
                  │
    ┌─────────────▼─────────────┐
    │ Application / UseCase       │
    │ 编排业务流程                │
    └─────────────▲─────────────┘
                  │
    ┌─────────────▼─────────────┐
    │ Domain                     │
    │ 聚合、实体、领域服务、事件 │
    └─────────────▲─────────────┘
                  │
    ┌─────────────▼─────────────┐
    │ Infrastructure             │
    │ 数据库、缓存、消息队列等   │
    └───────────────────────────┘
    
  3. 代码与业务语言一致

    • 所有类名、方法名、接口、事件都用统一语言。
    • 让业务人员也能看懂代码意图,沟通成本降低。
  4. 逐步演进

    • 不要把整个系统一次性改成 DDD。
    • 从核心业务开始,逐步拆分聚合和上下文。

第四部分:DDD 的落地案例(资产管理)

假设我们要实现资产策略匹配功能:

  1. 聚合根:Asset(资产)
  2. 值对象:PortInfo(端口信息)、IPRange
  3. 领域服务:StrategyService → 根据资产状态和端口匹配策略
  4. 仓储:AssetRepository → 负责持久化资产聚合
  5. 领域事件:AssetDiscovered → 当资产新上线时触发策略匹配
type Asset struct {
    ID string
    IP string
    Ports []PortInfo
}

func (a *Asset) UpdatePorts(ports []PortInfo) {
    a.Ports = ports
    events.Publish(AssetDiscovered{AssetID: a.ID})
}
  • 业务逻辑全部在聚合或领域服务中完成
  • Controller 只做输入输出,Infrastructure 只做数据存取
  • 团队对“资产上线 → 匹配策略 → 生成告警”流程有统一理解

第五部分:总结

DDD 的核心价值不在于复杂的建模术语,而在于让系统业务逻辑清晰、可演化、团队协作低成本

  • DDD 适合复杂业务核心
  • 先聚焦核心领域,再逐步扩展
  • 配合微服务、事件驱动、中台,才能支撑大型企业级系统