领域建模中容易出错的部分

💡 原文中文,约1800字,阅读约需5分钟。
📝

内容提要

领域建模是考虑实体和它们之间关系的方法。在领域驱动设计中,聚合是形成一致性边界的相关对象的集群。然而,聚合经常被误解和滥用,导致复杂性。建议以行为和业务规则为重点,而不是数据。不要使用不需要的数据结构和关系,以避免增加无用的复杂性。

🔎

延伸解读

从数据表到行为:聚合设计的起点错位

文章指出,许多团队在领域建模时先定义实体和值对象,再组合成聚合,这实际上是在构建数据表结构。例如晚餐托管应用中,菜单聚合包含晚餐ID列表和评论集合,看似合理,却只是数据关系的映射。聚合的真正价值在于维护一致性边界,而一致性需求来自业务行为。若不清楚系统要执行哪些状态变更、哪些不变量需要保护,直接划分聚合就是本末倒置。

行为驱动聚合:以晚餐预订为例

文章以晚餐托管系统为例,说明应关注业务规则:主人创建晚餐、客人预订或取消、座位数量有限等。这些行为决定了哪些数据需要封装在一起,以及聚合边界如何划分。例如,预订和取消操作需要保证座位数不超限,这要求相关状态在同一个聚合内保持一致。相反,若只根据数据表结构定义聚合,行为最终会退化为CRUD操作,失去领域模型的表达力。

避免过度使用聚合:不需要时勿增加复杂性

文章提醒,聚合常被误解和滥用,在不必要的情况下使用会引入复杂性。聚合适用于需要一致性边界的场景,即执行状态更改时要求整体一致持久化。如果业务行为简单,或数据之间没有强一致性要求,就不应强行套用聚合模式。设计时应先明确行为和不变量,再判断是否需要聚合,而不是为了建模而建模,否则只会增加无用的数据结构和关系。

❓

Q&A

领域建模时为什么不应该从定义实体和聚合开始?

因为这种方法是落后的。聚合是形成一致性边界的相关对象集群,但如果不了解行为,直接定义实体和聚合会导致你只是构建了数据表结构,而不是真正的聚合。行为驱动状态变化,决定聚合的定义和数据封装,所以应该从行为和业务规则出发。

在领域驱动设计中,聚合到底是什么?

聚合是形成一致性边界的相关对象(实体和值对象)的集群。聚合根是一个实体,是通往聚合的网关,所有与消费者/调用者的交互都通过根实体完成。聚合用于需要一致性边界时,确保状态更改作为一个整体一致地持久化。

为什么说聚合经常被误解和滥用?

因为人们常常在不应该使用聚合的情况下使用它,导致复杂性增加。例如,在未明确行为的情况下,通过穷举实体和值对象来定义聚合,最终只是得到了数据表结构,而不是真正的聚合。聚合应该只在需要一致性边界时使用。

行为驱动设计在领域建模中如何体现?

行为驱动设计关注业务规则和状态变化,而不是数据结构。例如,在晚餐托管应用中,需要关注是否有主人、客人预订和取消、座位限制等行为。这些行为决定了实体和值对象中需要哪些数据,进而指导聚合的定义。

如何避免在领域建模中增加无用的复杂性?

不要使用不需要的数据结构和关系。当你不需要聚合时就不要使用它,否则只会增加无用的复杂性。应该以行为和业务规则为中心,只定义实际功能所需的数据和封装。

晚餐托管应用的例子说明了什么建模问题?

该例子说明,如果从实体出发,穷举聚合根的可能性,最终得到的只是数据表结构,而不是聚合。例如,将菜单聚合中的晚餐转换为值对象并引用晚餐聚合,这仍然是数据驱动的做法。正确的做法是先明确行为,如预订、取消、座位限制等,再定义聚合。

🏷️

标签

➡️

继续阅读