一、全书概览
这本书不是 Eric Evans《Domain-Driven Design》的中文翻译或简单复述,而是一本面向中国开发者的 DDD 落地实战指南。王红亮结合自己多年的企业级项目经验,把 DDD 的核心思想拆解成可操作的步骤——从业务建模、领域划分、限界上下文,到代码层面的聚合、实体、值对象、领域服务的实现,再到微服务架构下的 DDD 应用,形成了一套完整的方法论闭环。
全书最大的价值在于把抽象的 DDD 概念具象化。Eric Evans 的原著偏理论,很多概念(如 Ubiquitous Language、Bounded Context)读完之后"懂了但不会用"。王红亮用电商订单、物流追踪、金融支付等国内开发者熟悉的业务场景作为例子,一步步演示怎么从需求文档里提取领域模型,怎么画领域事件风暴图,怎么把领域模型映射到代码结构,怎么在微服务边界划定中做取舍。
全书大约 16 章,结构大致分为四个部分:
| 部分 | 内容 | 章节范围 | |------|------|----------| | 理论奠基 | DDD 核心概念、战略设计 vs 战术设计 | 第 1-4 章 | | 业务建模 | 领域事件风暴、领域模型构建、上下文映射 | 第 5-8 章 | | 架构落地 | 聚合设计、领域服务、应用服务、基础设施层 | 第 9-12 章 | | 工程实践 | 微服务集成、CQRS、事件驱动、案例实战 | 第 13-16 章 |
适合谁读? 有 2-3 年以上后端开发经验、做过中大型项目、对"贫血模型 vs 充血模型"有困惑、想在实际项目中应用 DDD 但不知道从哪下手的开发者。纯新手可能会觉得某些概念跳跃太快,建议先读完 Evans 原著的前 5 章再来看这本。
不推荐谁读? 刚入门的初级开发者——这本书不会教你 CRUD 怎么写,它解决的是"项目复杂到一定程度之后怎么组织代码和业务逻辑"的问题。
二、逐章要点
第 1 章:为什么需要领域驱动设计
这一章从"软件开发的根本矛盾"讲起:业务复杂度只会越来越高,而我们的架构能力往往跟不上。作者用一组数据说明问题——一个典型的电商系统,上线 3 年后,代码量从 10 万行膨胀到 200 万行,但其中真正处理业务逻辑的代码不到 20%,剩下的全是胶水代码、重复代码和历史包袱。
"大部分系统的失败不是因为技术选型错了,而是因为业务理解错了。"
本章核心观点:
- [x] 技术架构解决的是"怎么跑"的问题,领域设计解决的是"跑什么"的问题
- [x] DDD 不是银弹,它解决的是业务复杂度高、需求变更频繁的场景
- [x] 分层架构(MVC)在小项目里够用,但在复杂业务面前会变成"大泥球"
| 症状 | 说明 | DDD 如何应对 | |------|------|-------------| | 需求反复改,每次改动牵一发动全身 | 领域边界不清晰 | 通过限界上下文隔离变更范围 | | 同一个概念在代码里有 5 种命名 | 缺乏统一语言 | 强制推行 Ubiquitous Language | | Service 类膨胀到几千行 | 业务逻辑散落在各层 | 领域模型承载业务,应用层只做编排 | | 改一个小 bug 要改 3 个微服务 | 微服务拆分粒度不合理 | 按领域边界拆分,而非按技术功能拆 |
第 2 章:领域驱动设计的核心思想
DDD 的三大支柱:统一语言(Ubiquitous Language)、限界上下文(Bounded Context)、领域模型(Domain Model)。作者花了大量篇幅解释这三者的关系——统一语言是沟通工具,限界上下文是划分边界,领域模型是设计产出。三者缺一不可。
"如果开发人员和业务专家对同一个词的理解都不一样,那代码写出来注定是错的。"
书中用了一个电商场景:业务说"下单",开发理解为"创建订单记录",产品理解为"锁定库存+生成支付单+推送消息"。三个人说的是同一件事,但脑子里是完全不同的流程。这就是没有统一语言的典型后果。
- [x] 统一语言不是文档,是活在代码里的命名约定
- [x] 限界上下文的边界不是技术边界,是业务语义边界
- [x] 领域模型不是数据库表结构的映射,是业务规则的编码表达
第 3 章:战略设计与战术设计
这是 DDD 方法论的骨架章节。战略设计解决"系统怎么分"的问题,战术设计解决"模块怎么写"的问题。
战略设计的核心产出物:
| 产出物 | 作用 | 典型工具 | |--------|------|----------| | 子域划分 | 识别核心/支撑/通用子域 | 业务分析 + 头脑风暴 | | 限界上下文 | 划定模型边界 | 上下文映射图 | | 上下文映射 | 定义上下文间关系 | ACL、防腐层、共享内核等模式 |
战术设计的核心元素:
- 实体(Entity):有唯一标识、有生命周期、可变(如订单)
- 值对象(Value Object):无标识、不可变、用属性判断相等(如金额、地址)
- 聚合(Aggregate):一组必须保持一致性的对象集合,有且只有一个聚合根
- 领域服务(Domain Service):不属于任何实体的业务逻辑
- 领域事件(Domain Event):领域中发生的重要事情,用于解耦
"聚合的设计是 DDD 中最难的部分。聚合太大,并发性能差;聚合太小,一致性保证不了。"
第 4 章:统一语言的实践
这一章讲怎么在真实项目里推行统一语言,而不仅仅是"大家开会统一一下命名"这么简单。作者给出的方法很接地气:
- 事件风暴工作坊:把业务专家和开发人员关在一个房间里,用彩色贴纸在白板上梳理业务流程
- 领域词汇表:维护一份所有人在用的术语表,代码里的类名、方法名必须和词汇表一致
- 代码即文档:好的领域模型本身就是最准确的业务文档
作者举了一个实际案例:某金融项目的"账户"概念,风控团队说的账户、财务团队说的账户、技术团队说的账户完全是三个不同的东西。最终通过限界上下文划分,拆成风控账户、财务账户、技术账户三个独立的领域模型,各自演进,互不干扰。
- [x] 统一语言从事件风暴开始,但必须落地到代码命名
- [x] 当发现同一个词在不同上下文有不同含义时,不是统一它,而是拆分它
- [x] 拒绝"技术黑话污染业务语言"——不要在业务讨论里说"这张表加个字段"
第 5 章:领域事件风暴
事件风暴(Event Storming)是书中重点推荐的建模方法,源自 Alberto Brandolini。这一章详细介绍了事件风暴的操作步骤和实战技巧。
核心流程:
"先找事件,再找命令,最后找聚合。这个顺序不能反。"
- 橙色贴纸:写下所有领域事件(过去式,如"订单已创建""支付已成功")
- 蓝色贴纸:触发事件的命令(如"创建订单""确认支付")
- 黄色贴纸:命令的发起者(角色/外部系统)
- 紫色贴纸:策略和业务规则(如"库存不足时取消订单")
- 绿色贴纸:读模型(命令执行时需要查询的数据)
- 红色贴纸:外部系统依赖(如支付网关、短信平台)
- [x] 事件风暴不需要 IT 技能,业务专家主导,技术人员辅助
- [x] 一场典型的事件风暴需要 4-6 小时,建议用整块时间
- [x] 事件风暴的产出物不是最终设计,而是领域模型的草稿
第 6 章:领域模型构建
从事件风暴的贴纸墙到代码里的领域模型,中间有一段路要走。这一章讲的是这段路怎么走。
作者提出的建模流程:
| 步骤 | 输入 | 输出 | 关键问题 | |------|------|------|----------| | 识别聚合 | 事件 + 命令 | 聚合列表 | 哪些对象必须一起变更? | | 确定聚合根 | 聚合内对象 | 聚合根 | 谁是这个聚合的入口? | | 设计实体 | 聚合根 + 业务规则 | 实体类 | 哪些对象有独立生命周期? | | 提取值对象 | 实体属性 | 值对象类 | 哪些属性组合起来才有业务含义? | | 定义领域服务 | 跨聚合逻辑 | 服务类 | 哪些逻辑不属于任何实体? |
一个实际的设计决策:订单里的"收货地址"应该是实体还是值对象?作者的判断标准很简单——如果业务上需要独立管理地址(比如用户的默认地址列表),那就抽成实体;如果地址只是订单的一个属性,改了不影响其他订单,那就做成值对象。大多数电商场景下,订单里的地址做成值对象就够了。
"值对象的好处是你不用管它,它是不可变的,天然线程安全,天然可缓存。"
第 7 章:限界上下文与上下文映射
这一章是战略设计的核心。限界上下文(Bounded Context)是 DDD 划分系统边界的核心手段,但很多人搞不清楚它和微服务的关系——限界上下文是逻辑边界,微服务是物理边界,两者可以一对多,也可以多对一。
上下文映射的几种核心模式:
| 模式 | 含义 | 适用场景 | |------|------|----------| | 共享内核(Shared Kernel) | 两个上下文共享一部分模型 | 团队紧密协作,模型高度一致 | | 客户-供应商(Customer-Supplier) | 下游提需求,上游决定怎么做 | 上下游在同一组织内 | | 遵奉者(Conformist) | 下游完全采用上游模型 | 下游没有谈判能力 | | 防腐层(Anti-Corruption Layer, ACL) | 下游建适配层隔离上游模型 | 集成遗留系统或第三方 | | 开放主机服务(OHS) | 上游提供标准化 API | 对外提供服务的子系统 | | 发布语言(Published Language) | 上下文间用统一的数据格式通信 | 多个团队协作的大型系统 |
- [x] 一个限界上下文内部,领域模型是自洽的、一致的
- [x] 跨上下文通信,优先用领域事件,其次用应用服务接口
- [x] 防腐层是集成遗留系统时最有价值的模式,不要省
第 8 章:聚合设计深入
聚合设计是 DDD 实战中争议最大的部分。聚合太大,一次加载和持久化的对象太多,性能扛不住;聚合太小,一致性保证不了,数据可能出错。
作者给出的聚合设计原则:
- 聚合要小:一个聚合理想情况下包含 1 个聚合根 + 少量实体/值对象
- 通过 ID 引用,不通过对象引用:跨聚合只保存对方 ID,需要数据时再查
- 一个事务只修改一个聚合:跨聚合的一致性用最终一致性(领域事件)保证
- 聚合根是唯一入口:外部不能直接修改聚合内部对象
"如果你发现一个聚合里有超过 5 个实体,大概率是你的边界画错了。"
书中对比了两种常见的聚合设计错误:
- 过度聚合:把"订单 + 订单项 + 商品 + 库存"放在一个聚合里——一个订单要加载整个商品目录,荒谬
- 碎片聚合:把"订单"拆成"订单头"和"订单行"两个聚合——修改订单行要同时更新订单头,一致性怎么保证?
正确的做法:订单 + 订单项组成一个聚合(它们必须一起变更),商品和库存分别是独立的聚合。
第 9 章:领域服务的应用场景
领域服务是 DDD 里最容易滥用的概念。作者反复强调:只有当一个业务逻辑不属于任何实体时,才使用领域服务。
典型的领域服务场景:
- 跨聚合的业务规则:如"下单时检查库存是否充足"(涉及订单聚合和库存聚合)
- 纯计算逻辑:如"计算运费"(输入地址和重量,输出金额,无状态)
- 外部系统编排:如"发起支付"(需要调用支付网关,但业务规则在领域层)
一个容易犯的错:把所有"Service"类都叫领域服务。作者明确区分了三种服务:
| 服务类型 | 所在层 | 职责 | 例子 | |--------|--------|------|------| | 领域服务 | 领域层 | 纯业务逻辑,不依赖基础设施 | 运费计算服务 | | 应用服务 | 应用层 | 编排领域对象,协调事务 | 创建订单应用服务 | | 基础设施服务 | 基础设施层 | 技术实现(发邮件、调接口) | 短信发送服务 |
第 10 章:应用层与领域层的协作
这一章讲的是分层架构中应用层和领域层的职责划分。应用层是"指挥官",负责接收请求、调用领域对象、管理事务、发布事件;领域层是"士兵",负责执行具体的业务规则。
"应用服务应该薄到让你觉得'这玩意儿有什么用',但它就是有用——它让领域层保持纯粹。"
典型的应用服务代码结构(伪代码):
创建订单应用服务:
1. 校验请求参数
2. 调用仓库加载商品和用户
3. 创建订单聚合(领域逻辑在这里)
4. 通过仓库持久化订单
5. 发布"订单已创建"领域事件
6. 返回结果
注意:第 3 步是领域逻辑,应该放在订单聚合内部(order.create()),而不是应用服务里。应用服务只负责编排,不负责业务判断。
- [x] 应用服务不包含业务逻辑——如果发现有
if判断业务规则,说明写错了地方 - [x] 领域层不依赖基础设施层——通过接口(端口)解耦,具体实现在基础设施层
- [x] 事务边界和应用服务方法边界保持一致
第 11 章:CQRS 与事件驱动架构
CQRS(Command Query Responsibility Segregation)是 DDD 实战中经常搭配使用的架构模式。作者没有把 CQRS 当成必选项,而是明确给出了适用条件:
什么时候用 CQRS:
- 读操作和写操作的性能要求差异大(如写操作 QPS 100,读操作 QPS 10000)
- 读模型和写模型的结构差异大(如写端是关系型,读端是 Elasticsearch)
- 需要异步处理写操作(如订单创建后异步通知库存、物流)
什么时候不用 CQRS:
- CRUD 为主的简单业务
- 团队规模小(3-5 人),维护两套模型的成本太高
- 读写比例接近 1:1 的场景
"CQRS 不是默认选项,它是当你遇到了读写不平衡的问题时才考虑的优化手段。"
第 12 章:领域事件的落地实现
领域事件是 DDD 中实现解耦的核心机制。这一章从"什么是领域事件"讲到"怎么在生产环境中可靠地发布和消费领域事件"。
领域事件的三个保证:
| 保证 | 含义 | 实现方式 | |------|------|----------| | 必须发生 | 事件不能丢失 | 事务内写入事件表,异步消费 | | 恰好一次 | 事件不能重复消费 | 消费端幂等性设计(唯一键 + 状态检查) | | 有序 | 相关事件的顺序不能乱 | 按聚合 ID 分区,同一聚合内事件有序 |
作者推荐的实现方案:事务发件箱模式(Transactional Outbox)——在同一个数据库事务中写入业务数据和事件记录,再由后台任务轮询事件表、发布到消息队列。这个模式牺牲了一点实时性(通常延迟几十毫秒到几秒),但换来了可靠性。
第 13 章:微服务架构下的 DDD
这一章回答了一个关键问题:限界上下文怎么映射到微服务?
作者的观点很明确:
"一个限界上下文对应一个微服务"是理想状态,但现实往往是"一个限界上下文拆成 2-3 个微服务"或"3-4 个限界上下文合并成 1 个微服务"。原因是微服务拆分还要考虑团队规模、部署成本、数据量等因素。
微服务拆分的决策矩阵:
| 因素 | 倾向合并 | 倾向拆分 | |------|----------|----------| | 团队人数 | < 5 人 | > 10 人 | | 变更频率 | 高度耦合,同时变更 | 独立演进 | | 性能要求 | 相近 | 差异大 | | 数据量 | 小(< 100 万条) | 大(> 1000 万条) | | 故障隔离 | 允许一起挂 | 必须隔离 |
第 14 章:遗留系统的 DDD 改造
这是全书最接地气的一章。不是每个项目都能从零开始做 DDD,大多数开发者的日常是在屎山代码上修修补补。
作者提出的"绞杀者模式"(Strangler Fig Pattern)改造路线:
- 识别子域:分析现有系统,找出哪些是核心域、哪些是通用域
- 划定限界上下文:在现有代码里找到相对独立的模块边界
- 建防腐层:新代码和旧代码之间加一层适配,新代码用新模型,旧代码不动
- 逐步迁移:每次迭代迁移一个上下文,旧功能通过防腐层委托给新实现
- 最终替换:当所有上下文都迁移完毕,删除旧代码
- [x] 不要试图一次性重写——失败的案例比成功的多十倍
- [x] 防腐层是新旧代码共存的唯一可行方案
- [x] 遗留系统改造的 KPI 不是"代码多干净",而是"业务不中断"
第 15 章:DDD 与测试驱动开发
DDD 和 TDD 是天然搭档。领域模型是业务规则的编码,业务规则天然可以写成测试用例。
作者推荐的测试分层策略:
| 测试类型 | 覆盖范围 | 数量占比 | 执行速度 | |----------|----------|----------|----------| | 单元测试 | 领域模型(实体、值对象、领域服务) | 70% | 毫秒级 | | 集成测试 | 应用服务 + 仓库 | 20% | 秒级 | | 端到端测试 | API 接口 | 10% | 十秒级 |
"如果你给领域模型写了单元测试,你会发现聚合设计的问题——一个聚合如果需要 mock 太多依赖,大概率是聚合太大了。"
第 16 章:完整案例实战
最后一章用一个电商下单流程的完整案例,把前面 15 章的内容串起来。从事件风暴画贴纸,到领域模型设计,到代码实现,到微服务拆分,全流程走一遍。
案例的核心领域模型:
- 订单上下文:订单聚合(订单 + 订单项)、订单状态机、运费计算服务
- 库存上下文:库存聚合、库存预占/释放逻辑
- 支付上下文:支付单聚合、支付渠道适配
- 物流上下文:运单聚合、物流轨迹跟踪
三个上下文之间的通信方式:
- 订单 → 库存:同步调用(下单时必须确认库存)
- 订单 → 支付:领域事件("订单已创建"触发支付单生成)
- 支付 → 物流:领域事件("支付已成功"触发物流单创建)
三、关键概念速查
1. 统一语言(Ubiquitous Language)
团队(包括业务专家和技术人员)共同使用的、在代码中直接体现的术语体系。不是写完代码后补的文档,而是从需求分析阶段就开始建立的命名约定。类名、方法名、变量名都必须使用统一语言中的术语。
2. 限界上下文(Bounded Context)
领域模型的边界。在同一个限界上下文内,一个术语只有一个含义,一个模型只有一种解释。跨上下文时,同一个概念可能有不同的表示方式(如订单上下文的"用户"是 User 实体,物流上下文的"用户"只是收货人姓名和电话)。
3. 聚合(Aggregate)
一组必须保持事务一致性的领域对象。聚合有且只有一个聚合根(外部访问的唯一入口),聚合内部的实体和值对象不能被外部直接修改。一个事务只能修改一个聚合。
4. 聚合根(Aggregate Root)
聚合的入口和代言人。外部对象只能通过聚合根的方法来修改聚合内部的状态。聚合根负责维护聚合内部的不变性约束(业务规则)。
5. 领域事件(Domain Event)
领域中"已经发生的重要事情"。用于解耦不同的聚合和限界上下文。事件是过去时的陈述(如"订单已创建"),携带事件发生时的关键业务数据,由事件消费者异步处理。
6. 防腐层(Anti-Corruption Layer, ACL)
在限界上下文边界处建立的适配层,防止外部模型"污染"内部领域模型。典型场景:集成第三方系统、对接遗留系统。防腐层把外部数据结构转换成内部领域模型,外部接口变更时只需修改防腐层。
7. 领域服务(Domain Service)
不属于任何实体或值对象的业务逻辑。无状态的纯业务操作。注意和应用服务区分——领域服务承载业务规则,应用服务负责编排流程。
四、核心框架/模型
DDD 分层架构
┌─────────────────────────────────┐
│ 接口层(Interface) │ ← 接收请求,返回响应
├─────────────────────────────────┤
│ 应用层(Application) │ ← 编排流程,管理事务
├─────────────────────────────────┤
│ 领域层(Domain) │ ← 业务逻辑(核心)
├─────────────────────────────────┤
│ 基础设施层(Infrastructure) │ ← 技术实现
└─────────────────────────────────┘
依赖方向:接口层 → 应用层 → 领域层 ← 基础设施层。领域层不依赖任何外层。
领域建模流程
事件风暴 → 识别子域 → 划分限界上下文 → 定义上下文映射
↓
设计聚合和实体
↓
提取值对象和领域服务
↓
代码实现 + 单元测试
一致性模型选择
| 一致性级别 | 范围 | 实现方式 | 延迟 | |-----------|------|----------|------| | 强一致性 | 聚合内部 | 本地事务 | 毫秒 | | 最终一致性 | 跨聚合 | 领域事件 + 消息队列 | 秒~分钟 | | 最终一致性 | 跨上下文 | 领域事件 + 事件总线 | 秒~分钟 |
代码结构参考(Java/包结构)
com.example.ordercontext/
├── application/ # 应用服务
│ ├── command/ # 命令对象
│ ├── query/ # 查询对象
│ └── eventhandler/ # 事件处理器
├── domain/ # 领域层
│ ├── model/ # 聚合、实体、值对象
│ ├── service/ # 领域服务
│ ├── event/ # 领域事件
│ ├── repository/ # 仓库接口(只定义接口)
│ └── factory/ # 工厂(复杂对象创建)
├── infrastructure/ # 基础设施层
│ ├── persistence/ # 仓库实现(MyBatis/JPA)
│ ├── messaging/ # 消息队列实现
│ └── external/ # 外部系统适配
└── interface/ # 接口层
├── api/ # REST/GraphQL
├── dto/ # 数据传输对象
└── assembler/ # DTO 与领域对象转换
五、金句摘录
-
"大部分系统的失败不是因为技术选型错了,而是因为业务理解错了。" —— 这句话值得贴在每一个开发工位上。多少项目花了几个月搞微服务、搞容器化、搞 DevOps,最后发现做出来的东西业务根本不需要。
-
"聚合的设计是 DDD 中最难的部分。聚合太大,并发性能差;聚合太小,一致性保证不了。" —— 没有标准答案,只能在业务场景中反复权衡。作者给出的建议是"从小开始,遇到性能问题再拆"。
-
"统一语言不是文档,是活在代码里的命名约定。" —— 如果你的代码里到处是
userInfoVO、UserDTO、UserEntity、UserDO,而业务专家只说"用户",那说明统一语言没有落地。 -
"防腐层是新旧代码共存的唯一可行方案。" —— 遗留系统改造时,不要幻想一次性重写。建一个防腐层,新代码用新模型,旧代码通过防腐层调用,逐步迁移。
-
"如果你发现一个聚合里有超过 5 个实体,大概率是你的边界画错了。" —— 这个数字不是硬性规定,但超过 5 个实体通常意味着聚合承担了太多职责。
-
"应用服务应该薄到让你觉得'这玩意儿有什么用',但它就是有用——它让领域层保持纯粹。" —— 好的应用服务就像好的管理层:不干具体的活,但确保正确的人干正确的事。
-
"CQRS 不是默认选项,它是当你遇到了读写不平衡的问题时才考虑的优化手段。" —— 很多人把 CQRS 当成 DDD 的标配,其实大部分项目根本用不上。
六、行动清单
每天可以做的事
- [ ] 检查最近写的代码,类名和方法名是否用了业务术语(而不是技术术语)
- [ ] 看到新的需求文档时,先问自己:这个需求属于哪个限界上下文?
- [ ] 写代码前花 5 分钟画一下涉及的领域对象和它们之间的关系
- [ ] 遇到一个新的 Service 类时,问自己:它是领域服务、应用服务,还是基础设施服务?
每周可以做的事
- [ ] 选一个现有模块,尝试识别它的聚合根和聚合边界
- [ ] 和业务同事聊一次,确认你们对核心概念的理解是否一致
- [ ] 审查代码时,关注是否有跨聚合的直接对象引用(应该用 ID 引用)
- [ ] 写 2-3 个领域模型的单元测试,用 Given-When-Then 格式描述业务规则
每月可以做的事
- [ ] 组织或参与一次轻量级的事件风暴(2-3 小时,用在线白板也行)
- [ ] 画一张当前系统的限界上下文地图,标注上下文之间的关系
- [ ] 选一个最痛的模块,尝试用 DDD 的方式重构(不用全部重写,先从防腐层开始)
- [ ] 读一篇 DDD 实战相关的技术博客或案例文章,对比书中的方法论看实际项目怎么做取舍
七、一句话总结
这本书的价值不在于提出了什么新理论,而在于把 DDD 从"懂了但不会用"变成了"看完就能照着做"——用中国开发者的语言,讲中国开发者会遇到的业务场景,给中国开发者能落地的实操方案。
八、读者热议
"事件风暴真的有用吗?感觉像是在浪费时间贴纸。"
不少开发者对事件风暴持怀疑态度,觉得一群人围着白板贴彩色纸效率太低。但从实际反馈来看,事件风暴最大的价值不是产出设计文档,而是让业务和技术人员真正坐在一起讨论业务。很多"技术实现不了"的需求,在事件风暴过程中发现根本就是业务规则没想清楚。贴纸只是工具,沟通才是目的。
"DDD 是不是只适合大公司大团队?小团队用不上?"
这是个好问题。DDD 确实在大团队大系统里价值更明显,但小团队同样受益于 DDD 的核心思想——统一语言让你少写注释少吵架,聚合设计让你的代码好测试好维护,限界上下文让你的模块边界清晰。区别只是投入程度不同:大团队做完整的事件风暴和上下文映射,小团队可以简化成"先统一命名、再划模块边界"。
"贫血模型真的那么差吗?我们团队一直在用,也没觉得有什么问题。"
贫血模型(Anemic Domain Model)是国内 Java 项目的默认做法——实体只有 getter/setter,业务逻辑全在 Service 层。这种方式在小项目里确实没问题,甚至开发速度更快。但当一个 Service 类膨胀到 1000 行以上,你会发现"改一个地方要改五个文件"成了常态。充血模型的好处是把相关的数据和行为放在一起,改起来不用到处跳。从贫血迁移到充血不需要一步到位,可以先从核心域开始尝试。
笔记生成:2026-04-28 by 喵喵 🐈
相关笔记
同作者仅有此篇 同主题: