如何用 DDD/CQRS/ES 建模仓库应用程序?

How to model a warehouse application with DDD/CQRS/ES?

我们要为仓库应用程序建模。假设我们确定了以下真实世界对象:

存在以下限制条件:

一开始我们有一个操作:

当然这是非常简化的。

应该如何建模?

我认为 Stockitem 可能是一个价值对象。一种解决方案是将整个仓库建模为具有调色板和隔间实体的集合体。在这种情况下,关于其约束(不变量)的移动操作可以毫无问题地实施。但这种方法有明显的缺点。此聚合的事件日志将无限增长。由于聚合版本控制等原因,无法并行执行两个移动操作。而且从ddd的角度来说,我觉得不太合适。

另一种方法是使每个调色板和每个隔间都有自己的集合。那么move操作如何实现呢?

问题 1:谁加载引用的聚合?

我认为它应该坚持调色板。调色板可以引用它所在的隔间(它是一个聚合体)。但是这个引用是如何实现的(CQRS/ES)?移动命令的 Comandhandler 显然将从调色板存储库加载调色板聚合并调用其上的移动方法。谁加载引用的隔间?谁装载它应该移动到的隔间?我读到聚合不应访问存储库。 commandhandler 是否应该加载两个隔间?隔间是否应该作为参数提供给 move 方法?或者 commandhandler 是否应该将当前隔间设置为调色板并将目标隔间作为参数?

问题2&3:聚合之间的约束和双向关联

约束条件如何?要检查目标隔间是否为空,隔间需要知道存储在其中的调色板。这是应该避免的双向关联。而且因为它们是不同的聚合,它们不能在同一个事务中更新。调色板是否触发域事件以通知隔间它将移动到它?它必须作为具有撤消操作的传奇来实现吗?如果两个动作冲突,一个获胜,但是由于旧隔间已满,所以无法将松散的调色板移回原处怎么办?

对于一个非常简单的问题,这一切对我来说似乎都非常复杂。

在书籍和示例中,一切似乎都很清楚。但是如果我尝试使用它,我似乎做错了。

有人可以指导我正确的方向吗?

您应该只开始对行为进行对象建模,根本不要考虑聚合和值对象。一旦您对所需的行为进行建模,您就会知道什么是实体、聚合、根和值对象。

Vaughn Vernon 的解释中,他明确表示,在做出这些决定之前,您需要弄清所需的细节。

问题 1

我认为除了这里的业务分析,你还需要做一些交易分析。

如果您的域是高度协作的(这是 DDD 推荐的),移动到给定隔间的频率如何?在跨越 2 Compartment 聚合(源和目标)的事务下发生 Move 操作是否可行?或者最终的一致性是否足够,源 Compartment 将通过调色板离开它的事件向世界发出信号,而目标 Compartment 稍后会以某种方式以异步方式通知调色板正在加入它?

调色板浮动 "in limbo" 一小段时间是完全可以接受的,这是您需要咨询领域专家的问题。

问题2

双向关联不是唯一的解决方案。您可以向 PaletteRepository 询问所有具有 CompartmentID X 的 Palettes。或者,Compartment 可以(应该)有一个 Palette ID 列表,而不是对它们的完整引用。

总的来说,我认为您应该先看看您问自己的所有设计问题是否有业务implication/answer。领域专家通常会对最终一致性是否现实或是否需要立即一致性、发生冲突时应该发生什么等问题发表有根据的意见。