两个聚合和一个事务——红皮书示例

Two aggregates and one transaction - the Red Book example

在红皮书中,Vernon 将 BacklogItem 和 Sprint 实体建模为单独的聚合。我看到了这种方法的优点,但有一种情况我无法理解。例如,我需要我的 Sprint 聚合来强制执行分配的最大项目限制。此外,BacklogItem 必须了解分配事实,以确保它不会分配给多个 Sprint。因此,将 BacklogItem 分配给 Sprint 会在一个事务中更改两个聚合,这不是我们想要做的。我看不到解决此问题的任何好方法。扩展聚合意味着使 BacklogItem 成为 Sprit 的内部部分。由于在其他聚合(发布、计划)中使用它的必要性,这没有任何意义。我想出的另一种方法是使用最终一致性并仅提醒管理员有关 BacklogItem 的双重分配。但我认为它是重要的聚合不变量,我想获得机会明确地强加它。

Another way I have come up with is to use eventual consistency and just alert administrator about double assignment of the BacklogItem.

我猜这是正确答案。

I need my Sprint aggregate to enforce maximum items assigned limit.

您可能忽略了一个重要的考虑因素:谁决定将哪些 BacklogItem 添加到 Sprint 中?这是模型自己做出的决定,还是由人(或模型之外的其他实体)做出的决定?

因为在大多数情况下,模型不应丢弃人工操作员做出的决定;并且它不应该强迫操作人员进行上下文转换以跳过模型的障碍。

There is no point to run that command if we know in advance that we exceeding Sprint items limit. If the Command Handler will perform that checking: $sprint->hasSpaceFor($item); wouldn't it be considered as knowledge leaking?

这里有几件事需要考虑。

一个是不属于聚合的数据是陈旧的;在您检查数据时,可能会有另一个命令处理程序更改该数据。这并不意味着检查它是错误的,但它确实意味着在命令处理程序中检查它并不明显比在其他地方检查它更好。

其次,您对不变量的检查取决于消息到达的顺序。人类操作员可能已经决定从 sprint 中删除一个项目以为新项目腾出空间——但如果消息的顺序在传输过程中发生变化(不可靠的消息传递传输),那么模型最终会拒绝应该是有效的命令.这样不好。

或者,消息可能按照发送的顺序到达。人类操作员知道这两个操作相互抵消,因此它发生的顺序无关紧要——但模型坚持以特定顺序报告决策。这就是跳铁环——该模型使工作变得更难,而不是更容易。

此外,将正确的项目放入冲刺中对业务的价值可能比弄清楚要删除哪一个更有价值。

关键见解:人工操作员现在处理业务的优先级,但生产中的模型运行反映了编写时的优先级-- 换句话说,该模型已经捕获了过去的优先级。所以你要小心让模型否决操作员。

更重要的是,您想了解在否决从人工操作员那里获得的消息时如何获得商业价值,并决定应在何处管理该责任 - 也许这是一个 UI 问题(试图减少数据输入错误的高成本?),而不是领域模型问题。