DDD(领域驱动设计)详解
DDD 的起源
-
提出者:Eric Evans
-
代表作:《Domain-Driven Design: Tackling Complexity in the Heart of Software》(《领域驱动设计:软件核心复杂性应对之道》)
-
时间:2003年
核心目标:
在复杂业务领域内,让系统的模型、设计和代码真正反映业务本质,而不是为了技术细节而妥协。
一句话总结:
✅ "以业务为中心建模,技术为业务服务。"
而不是
❌ "以数据库、接口、技术限制反向设计系统。"
后端 DDD 的核心概念
1. 领域(Domain)
-
领域是指特定业务知识的范围,比如“电商系统”、“保险理赔”、“金融风控”。
-
领域是整个系统的灵魂。
2. 领域模型(Domain Model)
-
领域模型是对现实世界业务规则、状态、行为的高度抽象,通常体现在代码中(类、方法、对象等)。
-
模型是活的,不是 UML 图,不是文档,而是可以跑的代码。
3. 战略设计(Strategic Design)
- 领域划分
-
核心领域(Core Domain):系统成功最关键的部分。
-
支撑子域(Supporting Subdomain):辅助核心领域,但本身不独特。
-
通用子域(Generic Subdomain):和业务无关的通用功能(如认证、日志)。
- 限界上下文(Bounded Context)
-
指一个明确的业务边界,在这个边界内,某个模型有统一的定义。
-
每个限界上下文内部模型一致,不同上下文之间可以存在模型冲突,需要翻译。
- 上下文映射(Context Mapping)
-
说明各个限界上下文之间如何交互,比如合作关系、上下游关系、开放主机服务、ACL防腐层等。
4. 战术设计(Tactical Design)
- 实体(Entity)
-
有唯一标识符(ID),生命周期长,状态可变。
- 值对象(Value Object)
-
无需 ID,根据属性值判等,不可变,比如 Money、Address。
- 聚合(Aggregate)
-
由实体和值对象组成的集合,有一个聚合根(Aggregate Root)作为入口。
- 仓储(Repository)
-
提供聚合的持久化接口(通常是数据库交互)。
- 领域服务(Domain Service)
-
某些业务逻辑不属于某一个实体,抽出来成为领域服务。
- 应用服务(Application Service)
-
负责协调领域对象,处理用户请求,返回响应,但不承载业务规则。
质疑:为什么后端要用 DDD?
✅ 适用场景:
-
系统业务极度复杂,无法用简单的 CRUD 应付,比如:
-
银行信贷系统
-
保险理赔系统
-
ERP、供应链管理系统
-
-
团队规模大,必须形成统一的业务语言和建模方式。
-
需要长期演进,保持系统可扩展、可理解。
❌ 不适用场景:
-
简单 CRUD 服务、信息展示系统、小型内部工具,不需要 DDD。
-
领域模型过重,反而增加开发和学习负担,得不偿失。
DDD 真正的挑战
-
高认知成本:要理解业务、建模,远比堆 API 难。
-
团队协作要求高:要有共同的领域语言,业务方、开发、测试、产品经理之间必须统一。
-
建模难度大:真正能建出好模型的人很少。
-
落地难度大:很多公司打着 DDD 旗号,实际上只是加了几层 service 目录而已。
我的专业观点
-
DDD不是银弹,是为复杂业务系统量身定制的方法,不是所有项目都应该用。
-
战略设计远比战术设计重要。不要一开始就沉迷 entity、repository,而是先搞清限界上下文和领域划分。
-
实践要渐进式引入。一开始可以局部使用 DDD 思想,随着团队熟悉后逐步扩展。
-
DDD讲究语言统一,产品经理、开发、测试都应该用同一套业务术语,否则 DDD会形同虚设。
-
不要迷信架构,DDD只是帮助你更好地服务业务,而不是成为炫耀的资本。
总结
后端 DDD 的精髓在于:以真实业务为中心进行建模,控制复杂度,提升长期演进能力。
真正掌握 DDD,不是掌握了一堆术语,而是能用业务语言自然地解释系统设计背后的每一个决策。