上一篇笔记讲了 DDD 的整体认识,这篇深入到 DDD 的第一个层次——战略设计。它是决定整个系统边界的关键一步。
什么是领域(Domain)
“领域”就是软件要解决的问题所在的业务范围。比如:
- 一个电商系统,领域是”在线交易”;
- 一个医院挂号系统,领域是”医疗服务”;
- 一个物流系统,领域是”货物运输”。
领域并不是一个抽象的大词,它是由一系列业务活动、规则、概念组成的。开发这个系统的人,本质上是在用代码重新描述这个领域。
子域(Subdomain):把领域拆小
一个真实的业务领域往往非常大。比如”电商”这个领域,包含商品、库存、订单、支付、营销、物流、会员…… 直接对整个领域建模会非常困难。所以战略设计的第一步,就是把大领域拆分成若干子域(Subdomain)。
子域一般分成三类:
| 类型 | 特点 | 例子(电商) |
|---|---|---|
| 核心子域 | 公司最有竞争力、最不能外包的部分 | 订单、交易 |
| 支撑子域 | 重要但非核心,可自研也可外包 | 库存、营销 |
| 通用子域 | 没有业务特性,行业通用,通常用现成方案 | 权限、日志、认证 |
拆分时最重要的一点是:资源要优先投给核心子域。核心子域是最值得投入精力的地方,通用子域直接用成熟方案(比如用现成的鉴权框架),没必要自己造轮子。
限界上下文(Bounded Context):真正的边界
如果说”子域”是业务视角的划分,那么”限界上下文”就是技术/实现视角的边界划分。
限界上下文是 DDD 里我认为最核心的概念。它的含义是:
一个限界上下文就是一个明确的边界,在这个边界内,模型、术语、规则是一致的。
回到之前”订单状态”的例子:电商团队的 订单 和物流团队的 订单,其实是两个不同限界上下文里的不同模型。
- 在交易上下文里,订单关注”是否支付、是否超时、是否关闭”;
- 在履约上下文里,订单关注”是否拣货、是否出库、是否签收”。
它们都叫”订单”,但关心的事实和规则完全不同。如果硬要用一个”大而全”的订单模型去覆盖所有场景,必然导致混乱。
为什么需要限界上下文?
核心原因:一个统一的模型无法满足所有场景。
不同场景对同一概念的需求是矛盾的。比如”商品”在销售上下文里需要”价格、促销”属性,在仓储上下文里需要”库存量、存放货架”属性。强行统一会让模型臃肿,也让每个团队都要迁就别人。
所以限界上下文的做法是:各自维护自己的模型,通过明确的上下文边界隔离复杂度。
上下文之间的集成
既然拆成了多个上下文,它们之间就需要协作。DDD 提供了一些**上下文映射模式(Context Mapping)**来定义协作关系,比如:
- 防腐层(Anti-Corruption Layer):隔离外部系统对自身模型的污染。
- 共享内核(Shared Kernel):两个上下文共享一小部分稳定模型。
- 开放主机服务(Open Host Service):通过公开 API 对外提供服务。
这些模式里,日常用得最多、也最实用的就是防腐层——当你的系统要对接一个模型很混乱的旧系统或第三方系统时,防腐层能把外部复杂性挡在边界之外。
统一语言(Ubiquitous Language)
战略设计里还有一个贯穿始终的概念——统一语言。
它要求业务人员和开发人员在同一个限界上下文内,使用完全一致的术语。业务说”下单”、“退款”、“驳回”,代码里就应该是 placeOrder、refund、reject,而不是 createOrder、payRollback、updateStatusToXxx。
统一语言的价值在于:当业务人员能读懂你的领域模型,代码和业务就真正对齐了。这也要求我们模型命名要贴近业务语言,而不是贴近数据库表名。
小结
战略设计回答了”系统边界在哪”:
- 用子域从业务视角拆分大领域,并识别出核心子域优先投入。
- 用限界上下文从实现视角划定模型边界,隔离复杂度。
- 用统一语言保证业务与代码术语一致。
下一步,进入 DDD 的第二个层次——战术设计,看看在某个上下文内部,实体、值对象、聚合这些战术概念怎么用。