CleanDDD 的定义
什么是 CleanDDD?
CleanDDD 即 Clean Domain-Driven Design,是基于领域驱动设计(DDD)的核心理念,经过概念简化和重构,形成的一套实用的软件工程指南,它包含四个重要组成部分:
- 一个价值取向
- 一组概念定义
- 一种建模方法
- 一套代码规范
CleanDDD 的目标
通过明确的概念和易于遵守的原则,避免代码快速腐化陷入混乱不可维护的困境,帮助开发者掌控复杂的软件系统,保持对软件系统和代码的掌控力,从而实现可持续的快速迭代和交付能力。
CleanDDD 的价值取向
保持边界明确是最重要的事。
CleanDDD Skills(AI Agent 支持)
我们提供了 cleanddd-skills 项目,面向 AI Agent 提供 CleanDDD 的能力支持与可复用技能集,便于在自动化场景中调用。
项目地址:
- https://github.com/netcorepal/cleanddd-skills
CleanDDD 的概念定义
- 聚合:负责独立维护业务核心数据和行为的对象集合,具有明确的边界和一致性规则。
- 领域事件:由聚合行为产生的、反映业务事件发生的对象,通常以过去式命名。
- 领域事件处理器:负责基于领域事件创建并发出相应的命令。
- 命令:由用户操作或系统事件触发的、请求修改聚合状态的对象。
- 命令处理器:负责操作聚合以实现业务需求。
- 查询与查询处理器:负责从聚合中获取数据以满足用户的查询需求。
- 定时任务:在特定时间或周期性地执行某些操作的任务,通常用于发出命令修改聚合状态。
- 集成事件:在不同系统之间传递信息的事件,通常由领域事件转化而来,并在 MQ 等消息中间件中传递。
- 集成事件处理器:处理集成事件并发出相应命令的组件,通常位于接收系统中。
CleanDDD 的建模方法
- 识别聚合
- 当识别到“创建 x”的需求时,很可能 x 就是一个聚合。
- 当发现 x 无法独立存在,需要依附到另一个实体时,x 可以定义为该实体的子实体。
- 识别命令与命令处理器
- 当某个操作需要修改聚合状态时,这个操作就可以定义为一个命令。
- 命令通常由以下情形触发:
- 用户操作(如通过 UI 提交表单)
- 领域事件处理器
- 定时任务
- 识别领域事件
- 领域事件通常以过去式命名,表示某个重要业务事件已经发生。
- 命名应反映业务含义,例如
OrderCreated、CustomerAddressUpdated。
- 识别领域事件处理器
- 当识别到“当做 x 操作后,要做 y 操作”的需求时,y 操作应由领域事件处理器触发。
- 每个领域事件处理器应专注于处理单一领域事件,确保职责清晰。
- 识别查询
- 当用户需要查看聚合数据时,这个操作就可以定义为查询。
- 当业务规则判断需要基于聚合数据时,这个操作也可以定义为查询。
CleanDDD 的代码规范
- 聚合
- 聚合之间不允许直接相互引用。
- 聚合之间不共享实体,即不允许通过子实体对象引用其他聚合。
- 聚合内对象只能通过聚合根或其子实体的方法进行修改。
- 聚合属性变更必须通过聚合的行为(方法)来完成。
- 领域事件
- 领域事件必须由聚合的行为产生。
- 命令处理器
- 命令处理器只能修改单个聚合。
- 事件处理器
- 一个事件处理器只能处理单个领域事件。
- 查询
- 不允许跨聚合的 Join 查询。
Q&A
CleanDDD 与 Clean Architecture 关系是怎样的?
CleanDDD 与 Clean Architecture 并无直接关系,在代码组织方式上有一定相似性,但两者的关注点和目标不同,涉及的分层概念也不完全相同。CleanDDD 的 Clean 更强调对复杂概念的简化与实践便捷性,而不是指代某种特定架构风格。
基于 CleanDDD 开发的软件,性能会不会很差?
不会。大部分业务系统是 I/O 密集且读多写少的场景。CleanDDD 强调聚合边界明确,不允许跨聚合直接引用和操作,会带来一定的信息冗余,从而减少跨聚合数据访问需求,反而提升整体性能。