DDD Day 1 — 战略设计:从业务视角划分领域
DDD Day 1 — 战略设计:从业务视角划分领域
今天开始复习 DDD 领域驱动设计,预计 3 天。这是 Day 1(战略设计)。
关键字:战略设计 / 子域划分 / 通用语言 / 限界上下文 / 事件风暴 / 上下文协作。
关联:AgentScope 4 PR 等开源贡献 / 之前项目里大量 DDD 影子,都跟 DDD 直接相关。
📌 一句话核心
"DDD 不是设计模式,不是架构,是一种服务业务的设计思想。战略设计 = 在业务视角下,回答 5 个核心问题,划清边界、统一语言、协作流畅。"
📌 为什么写这篇
最近几年 AI Coding 工程做得很多——但少了一个根本问题:这个领域应该怎么切?
不是"用 Agent 怎么写代码",而是"业务应该怎么分"——业务边界错了,Agent 写得越好,损失越大。
今天复习 DDD Day 1(战略设计)。
💎 第 1 部分:DDD 一句话定义
"DDD(领域驱动设计)= 围绕业务概念构建领域模型,控制业务复杂性的设计思想。"
1.1 核心要素
| 要素 | 含义 |
|---|---|
| 领域(Domain) | 业务要解决的问题空间(如"无线测试") |
| 模型(Model) | 对领域的抽象表达(用业务语言,而非技术术语) |
| 驱动(Driven) | 模型驱动代码,不是反过来 |
1.2 DDD 解决什么问题
| 问题 | 没有 DDD | 有 DDD |
|---|---|---|
| 业务理解 | 代码跟业务对不上 | 模型跟代码同构 |
| 团队沟通 | 各说各话 | 通用语言 |
| 服务划分 | 按技术分层 | 按业务能力 |
| 演进成本 | 改业务要改代码 | 模型稳,代码变 |
关键洞察:DDD 是一种思想,不是工具,不是框架,不是架构。
💎 第 2 部分:DDD 的两大设计层次
DDD
├─ 战略设计(Strategic Design) — 从业务视角出发
│
└─ 战术设计(Tactical Design) — 从技术视角出发| 层次 | 视角 | 关键产物 | 何时用 |
|---|---|---|---|
| 战略设计 | 业务 | 限界上下文、通用语言、领域模型 | 一开始(业务优先) |
| 战术设计 | 技术 | 聚合、实体、值对象、领域服务 | 战略定下来后 |
Day 1 重点:战略设计。Day 2 战术设计细节。
2.1 战略 vs 战术的"望远镜 vs 显微镜"
| 维度 | 战略设计 | 战术设计 |
|---|---|---|
| 视角 | 业务 | 技术 |
| 粒度 | 粗(几个上下文) | 细(几十上百个类) |
| 抽象度 | 高(业务术语) | 低(代码术语) |
| 稳定性 | 稳定(几年不变) | 易变(每次重构) |
| 参与者 | 业务方主导 | 工程师主导 |
| 产出 | 图 + 文档 | 代码 + 测试 |
关键洞察:战略设计 = 望远镜,战术设计 = 显微镜。
💎 第 3 部分:战略设计的 5 件事
战略设计要做 5 件事,这是 DDD 战略设计的核心:
[业务视角]
↓
① 建立业务领域模型
② 划分领域边界
③ 建立通用语言
④ 划分限界上下文
↓
[产出]
├─ 领域模型图
├─ 通用语言词典
└─ 限界上下文图3.1 第 1 件:从业务视角出发
核心原则:业务优先,技术其次。
- 不是"先建数据库",而是"先理解业务"
- 不是"先定 API",而是"先定领域模型"
- 不是"先分微服务",而是"先分业务能力"
3.2 第 2 件:建立业务领域模型
业务领域模型 = 用业务语言画的"业务地图"。
两类对象:
- 实体(Entity):有 ID 的对象(测试用例 = WO-XXX)
- 值对象(Value Object):无 ID 的对象(优先级 = {P0, P1, P2})
3.3 第 3 件:划分领域边界
领域边界 = 业务能力的边界。
例子:无线测试领域可划分成 4 块:
[无线测试领域]
├─ 测试设计(边界 1)
├─ 测试环境(边界 2)
├─ 测试执行(边界 3)
└─ 测试分析(边界 4)3.4 第 4 件:建立通用语言
通用语言 = 边界内的"官方语言"。
- 工程师、PM、客户都用这套语言
- 代码里的类名 / 方法名 / 表名都要跟这套语言一致
3.5 第 5 件:划分限界上下文
限界上下文 = 语义边界(下面第 5 部分单讲)。
💎 第 4 部分:子域 3 类划分 + 资源投入
领域不断划分,细分为不同的子域。根据重要性和功能属性,可以划分成 3 类。
4.1 子域的 3 类精确定义
| 子域类型 | 定义 | 关键属性 |
|---|---|---|
| 核心域(Core Domain) | 决定产品成功和核心竞争力的子域 | 差异化 + 核心竞争力 |
| 通用域(Generic Domain) | 个性化需求少的、被其他子域通用的功能子域 | 低差异化 + 高复用 |
| 支撑域(Supporting Domain) | 业务必需但不是核心的子域 | 中差异化 + 中复用 |
用户原话精炼:
- 核心域:"决定产品成功和核心竞争力"
- 通用域:"个性化需求少 + 被其他子域通用"
- 支撑域:"其他的"(核心域 + 通用域之外的全部)
4.2 资源投入原则
划分不同的子类,决定我们的资源投入,关注度和建设策略。
| 子域 | 资源投入 | 关注度 | 建设策略 |
|---|---|---|---|
| 核心域 | 80% 团队主力 | 最高(每天) | 自研 + 重兵投入 + 持续迭代 |
| 支撑域 | 15% 内部团队 | 中(周) | 部分自研 + 部分采购 |
| 通用域 | 5% 最小 | 低(季度) | 优先外包 / 套件 / 商业方案 |
核心原则:资源 = 子域重要性(不是工作量,不是代码量)。
4.3 实战案例:无线测试领域 4 子域
| 子域 | 类型 | 资源投入 |
|---|---|---|
| 测试设计 | 核心域 | 主力 |
| 测试环境 | 支撑域 | 中 |
| 测试执行 | 支撑域 | 中 |
| 测试分析 | 通用域 | 小 |
关键洞察:测试设计 = 核心域(差异化竞争力),测试分析 = 通用域(业界通用报表工具)。
4.4 子域识别决策矩阵
个性化高?
├─ 是 → 核心域 OR 支撑域
│ ├─ 决定核心竞争力 → 核心域
│ └─ 必需但不核心 → 支撑域
│
└─ 否 → 通用域(买 / 开源)子域识别 2 问:
- 这是我们产品差异化的来源吗?
- 这是用户买我们不买别人的原因吗?
两个都不是 → 不是核心域。
4.5 3 个常见误区
| 误区 | 后果 |
|---|---|
| 把所有子域都当核心域 | 资源平均,每个都做不好 |
| 核心域识别错误 | 在通用组件上花大精力 |
| 通用域也想做差异化 | 重复造轮子,资源浪费 |
"识别错误 = 战略失败。花错钱比少花钱更糟。"
💎 第 5 部分:通用语言精讲
通用语言 = 团队的统一语言,贯穿 DDD 设计的整个过程,让领域专家和开发无障碍沟通。
5.1 3 个核心要素
| 要素 | 含义 | 例子 |
|---|---|---|
| 术语(Terminology) | 业务概念的名称 | "用例"、"判据"、"工单"、"环境" |
| 用例场景(Use Case) | 业务发生的具体过程 | "用例已生成 → 评审 → 通过" |
| 统一性(Unification) | 同一概念只用一个词 | "WO-001"(不是"WO001" / "W001" / "工单 1") |
5.2 通用语言的 2 大要求
要求 1:限界上下文内术语统一,无二义性
反例:"用户"在"认证"上下文 = "User",在"营销"上下文 = "Customer"——工程师不知道两个是不同的概念。
要求 2:核心领域概念要在代码中有对应表达(代码即文档)
检验清单:
- "用例" → 类
TestCase? - "判据" → 类
PassCriteria? - "工单" → 类
WorkOrder? - "环境" → 类
Environment?
5.3 通用语言词典模板
# ubiquitous-language.yml
bounded_context: test-design
terms:
- name: 用例
english: TestCase
definition: 在某个测试场景下,验证某项功能的最小单元
code_class: src/domain/test_design/test_case.py::TestCase
aliases: [] # 禁用别名
deprecated_terms: ["测试用例", "Case", "测试项"]5.4 通用语言的 3 个反模式
| 反模式 | 表现 |
|---|---|
| 业务和代码用不同的词 | 业务说"用例",代码叫"TestCaseEntity" |
| 同一个概念多个名字 | "用例" / "测试用例" / "Case" 都用 |
| 只在文档里,不在代码里 | 文档说"用例 = TestCase",代码叫"CaseInfo" |
"DDD 失败的常见原因 = 通用语言没在代码里表达。"
5.5 元洞察
"通用语言不是名词表,是团队的'沟通操作系统'。"
"通用语言的价值不在于'用什么词',在于'所有人用同一个词'。"
💎 第 6 部分:限界上下文精讲
限界上下文 = 用来确定语义所在的边界,用来定义通用语言所在边界,用来细分领域。
6.1 一句话定义
"限界上下文 = 语义边界 + 通用语言边界 + 模型自治边界的三位一体。"
6.2 限界上下文的 3 重作用
| 作用 | 含义 |
|---|---|
| 确定语义所在的边界 | 1 个术语只在一个上下文里有明确含义 |
| 找到通用语言所在边界 | 1 个上下文有 1 套通用语言 |
| 细分领域 | 把大领域切成小领域,每个独立演进 |
6.3 核心洞察:必须翻译
┌─────────────────────┐ ┌─────────────────────┐
│ 测试设计上下文 │ │ 测试分析上下文 │
│ │ │ │
│ "用例" = TestCase │ ←→ │ "用例" = TestSample│
│ (待测试的最小单元) │ 翻译 │ (历史执行的样本) │
│ │ │ │
└─────────────────────┘ └─────────────────────┘
↑ ↑
[通用语言 1] [通用语言 2]关键洞察:同一个词在不同上下文里有不同含义,必须翻译——这是 DDD 的核心动作。
6.4 限界上下文的"内外有别"
| 维度 | 边界内 | 边界外 |
|---|---|---|
| 术语含义 | 唯一 | 可能多义 |
| 模型结构 | 可以自由改 | 必须防腐层保护 |
| 数据存储 | 自治 | 不能直接读别人表 |
| API 调用 | 直接调 | 通过防腐层 |
6.5 限界上下文的 3 个反模式
| 反模式 | 表现 |
|---|---|
| 边界模糊 | A 上下文直接读 B 上下文的内部表 |
| 边界过度拆分 | 每个方法 / 每个表都是一个上下文 |
| 边界未翻译 | 跨边界传内部对象,不翻译 |
6.6 通用语言 vs 限界上下文 的关系
[通用语言] ──── 一个上下文 = 一套通用语言
↓
[限界上下文] ──── 多个上下文 = 多个通用语言
↓
[上下文映射] ──── 上下文之间的关系"限界上下文 = 通用语言的边界。"
💎 第 7 部分:战略设计回答的 5 问
战略设计 = 这 5 个问题的答案集合:
| # | 问题 | 对应概念 | 产出 |
|---|---|---|---|
| 1 | 业务有哪些子域? | 子域划分 | 子域地图 |
| 2 | 核心域是什么? | 识别核心竞争力 | 核心域清单 |
| 3 | 边界在哪? | 限界上下文 | 上下文图 |
| 4 | 语言怎么统一? | 通用语言 | 语言词典 |
| 5 | 上下文之间怎么协作? | 上下文映射 | 协作模式表 |
7.1 上下文协作的 7 模式
| 模式 | 含义 |
|---|---|
| 共享内核 | 两个上下文共享一部分代码/模型 |
| 客户-供应商 | 上游提供数据,下游消费 |
| 防腐层 | 翻译外部模型,保护核心 |
| 开放主机服务 | 提供标准 API 给外部 |
| 发布语言 | 用标准格式交换数据(JSON/Protobuf) |
| 分离方式 | 两个上下文完全独立 |
| 大泥球 | 没有清晰边界(反模式) |
关键洞察:大多数上下文协作 = 防腐层 + 开放主机服务 + 发布语言。
💎 第 8 部分:领域模型的两层含义
同一个名词,两个完全不同的层级:
| 层级 | 视角 | 领域模型是 | 谁做 |
|---|---|---|---|
| 战略层 | 业务视角 | 领域地图 + 限界上下文 | 架构师 + 业务方 |
| 战术层 | 技术视角 | 聚合 + 实体 + 值对象 + 领域服务 | 工程师 |
8.1 战略层 vs 战术层 的 5 个差异
| 维度 | 战略层 | 战术层 |
|---|---|---|
| 粒度 | 粗(几个上下文) | 细(几十上百个类) |
| 抽象度 | 高(业务术语) | 低(代码术语) |
| 稳定性 | 稳定(几年不变) | 易变(每次重构) |
| 参与者 | 业务方主导 | 工程师主导 |
| 产出 | 图 + 文档 | 代码 + 测试 |
8.2 关键反模式
| 反模式 | 表现 |
|---|---|
| 战略层过度抽象 | 战略设计关注"边界在哪""语言怎么统一",不纠结"聚合根是什么" |
| 战术层过度发散 | 战术设计关注"这个聚合包含哪些实体",不画"业务全景图" |
"战略层过度抽象 + 战术层过度发散,都是反模式。"
💎 第 9 部分:DDD 在架构落地的 3 大模式
DDD 不绑定具体架构,但有 3 个最佳实践:微服务、事件驱动、六边形。
| 架构模式 | 核心思想 | 真实例子 |
|---|---|---|
| 微服务架构 | 按业务能力拆分服务,服务自治 | 我的指挥中心 |
| 事件驱动架构 | 通过事件解耦系统,异步优先 | AgentScope |
| 六边形架构 | 端口-适配器隔离业务和外部 | DDD 标准做法 |
9.1 微服务架构:按业务能力拆分
[DDD 限界上下文] [微服务]
[测试设计上下文] → [用例服务]
[测试环境上下文] → [环境服务]
[测试执行上下文] → [执行服务]
[测试分析上下文] → [分析服务]注意:限界上下文 ≠ 微服务(一个上下文可能拆 2 个微服务,或合并)。
9.2 事件驱动架构:异步解耦
[命令] → [聚合] → [领域事件] → [订阅者 1]
↘ [订阅者 2]
↘ [订阅者 3]AgentScope 内部用大量事件(Mem0 / Skill / Pipeline 触发等)做解耦。
9.3 六边形架构:端口-适配器
[外部系统 1] [外部系统 2] [外部系统 3]
↓ ↓ ↓
[适配器] [适配器] [适配器]
↓ ↓ ↓
════════════[ 端口 ]══════════
↓
[业务核心]9.4 三大架构对比
| 维度 | 微服务 | 事件驱动 | 六边形 |
|---|---|---|---|
| 核心思想 | 拆分服务 | 解耦系统 | 隔离业务 |
| 耦合度 | 服务间低 | 事件间低 | 业务与外部低 |
| 复杂度 | 高(运维) | 中(异步) | 低(代码) |
| 典型用 | Netflix | Kafka 生态 | DDD 标准做法 |
关键洞察:3 种架构不冲突,可组合——微服务内部用事件驱动 + 六边形。
💎 第 10 部分:战术设计的边界(预告 Day 2)
战术设计:由业务规则驱动,只是关注如何用代码表达领域模型。
10.1 战术设计的"是什么 / 不是什么"
| 战术设计是什么 | 战术设计不是什么 |
|---|---|
| 由业务规则驱动 | 不是技术驱动 |
| 只关注代码实现 | 不是写业务 |
| 表达领域模型 | 不是设计模型 |
| 服务于业务 | 不是炫技 |
10.2 战术设计 4 大核心概念
| 概念 | 一句话 |
|---|---|
| 聚合根(Aggregate Root) | "业务的最小完整单元" |
| 实体(Entity) | "生命周期跨越多个状态" |
| 值对象(Value Object) | "只描述特征,不变" |
| 领域服务(Domain Service) | "不属于任何实体的业务" |
Day 2 待展开:每个概念的详解 + 实战代码 + 仓储 + 防腐层。
📌 总结:DDD 战略设计的 3 句话
- 本质:战略设计 = 在业务视角下,回答 5 个核心问题(子域、核心域、边界、语言、协作)。
- 关键概念:通用语言是限内一致,限界上下文是限间差异——两者必须同时存在。
- 落地:3 大架构(微服务 / 事件驱动 / 六边形)可组合,核心域 80% 资源。
战略设计的输出清单
跟之前项目的关联
- 8 周深读 AgentScope 2.0 — 代码里大量 DDD 影子(
agent/= Agent 上下文,pipeline/= 业务流上下文) - 指挥中心 — 多模块拆分 = 微服务架构
- 工单状态机 S0-S6 — 业务流 = 状态机 = 限界上下文的具象化
关键洞察:之前项目不自觉地用到了 DDD 思想——只是没显式说出来。
给工程师的行动建议
| 时间 | 行动 |
|---|---|
| 本周 | 找一个项目,画一张"领域地图" |
| 本月 | 写一份"通用语言词典"(YAML) |
| 本季度 | 识别核心域,80% 资源集中 |
| 半年内 | 把通用语言落到代码里(类名 / 字段名) |
💬 最后一句话
"DDD 不是设计模式,不是架构,是一种服务业务的设计思想。"
"战略设计想清楚'做什么',战术设计想清楚'怎么做'。"
"业务优先,技术其次。代码跟业务同构,才是 DDD 的灵魂。"
DDD 战略设计的核心目标:把"领域怎么设计"这件事讲清楚——业务优先、技术其次。
这是 AI 时代最稀缺的视角——AI 让写代码变快,但没让"业务怎么切"变容易。