确定聚合根与 child 实体的最佳实践(DDD 建模)

Best practice on determining an aggregate root vs child entities (DDD Modelling)

我正在尝试对一组实体进行建模,并正在寻求确定域 object 是聚合根的候选者还是另一个聚合下的 child 实体列表的最佳实践根.

我有一个 Game object 代表一项通用运动的比赛。 Game 聚合当前有一个名为 GamePlayers 的 child 实体列表。这些 GamePlayer 个实体还有一个名为 GamePlayerHits 的 child 个实体的列表,其中记录了玩家在这项通用运动的比赛中被击中的位置。

Game 聚合上存在方法,例如 AddPlayer()RemovePlayer()GamePlayerHit 类型 GamePlayer 下的 child 个实体也有 AddHit().

等方法

我面临的问题是 GamePlayers 是否应该是其自身的聚合根并引用 Game 实体。 Game 最初可以在没有 GamePlayers 列表的情况下在技术上存在,在稍后的某个阶段它可能会被填充。 Game 也可以在没有任何玩家注册的情况下被删除或取消。这让我相信 GamePlayers 应该是基于我在网上看到的示例的自己的聚合。

这是我开始质疑围绕该主题的最佳实践的示例:

https://github.com/kgrzybek/modular-monolith-with-ddd

在这里,Meetings 聚合有一个 child MeetingAttendee 实体的列表,但是会议评论功能 MeetingComment 是它自己的聚合,并引用回 Meeting它属于。为了便于参考:

The Meeting class with MeetingAttendee child entities

The MeetingComment class as it's own aggregrate

在此示例中,为什么 MeetingComment 不是 Meeting 下的 child 实体的列表,并在 AddComment()DeleteComment() 上使用合适的方法主要聚合?我的假设是注释是可选的并且不需要验证聚合 and/or 这些实体需要通过 identifier/key 在其他地方引用,这不可能成为 child collection.

考虑到我上面关于游戏的示例,如何确定这是对这些聚合和实体建模的正确方法?是什么决定实体应该作为 child 实体还是作为单独的聚合根存在?

How does one determine taking in to account my example above regarding games which is the correct way to models these aggregates and entities? What determines if entities should exist as child entities or as a separate aggregate root?

存在域约束连接信息。

如果我们只需要捕获提供给我们的一堆信息,我们就不需要域模型;数据库足以捕获数据。

我们引入域模型是因为 (a) 我们需要确保新信息与我们已经捕获的信息兼容 and/or (b) 我们想要在本地计算派生值 (例如:因为在本地计算它们可以降低错误率)。

规则:如果我们有一个必须始终 成立的约束,并且该约束跨越多条信息,那么该信息必须全部包含在一个“聚合”中。

该规则的理由:必须更改受此类约束的信息 atomically。换句话说,我们希望所有这些信息都成为一个单元的一部分,以便进行数据更改。因此,管理此信息的域实体必须都是同一个“聚合”的一部分。

在取自蓝皮书 (Evans, 2003) 的货物运输示例中,我们对货物的误导 属性 有限制:如果最近记录的处理事件为真容器与最近分配的行程不一致。因此,这三条信息必须以原子方式存储(否则我们可能会面临存储数据不一致的风险),因此管理此信息的域实体必须都是同一聚合的一部分。

我倾向于想象一个图——数据是节点,每个约束都意味着连接受该约束约束的数据的边。然后我们的规则变成“每个图都必须完全包含在一个聚合中”。

单个聚合 可以 包含不止一个这样的图表,但在这样做时你也引入了 不是 固有的争论到域——这是“偶然复杂性”的一种形式。