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

时间:2017-06-04 14:34:06

标签: architecture domain-driven-design cqrs aggregateroot

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

1 个答案:

答案 0 :(得分:2)

  

我提出的另一种方法是使用最终的一致性,只需提醒管理员有关BacklogItem的双重赋值。

我的猜测是这是正确的答案。

  

我需要我的Sprint聚合来强制执行最大项目分配限制。

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

因为在很大程度上,模型不应该放弃人类操作员做出的决定;并且它不应该强迫人类操作员通过环境转移来跳过模型的箍。

  

如果事先知道我们超出Sprint项目限制,那么运行该命令是没有意义的。如果命令处理程序将执行该检查:$ sprint-> hasSpaceFor($ item);不会被视为知识泄漏吗?

这里有几点需要考虑。

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

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

或者,消息可能按照发送的顺序到达。人工操作员知道两个操作被取消,因此它发生的顺序无关紧要 - 但模型坚持要按特定顺序报告决策。这是箍跳 - 模型正在使工作更难,而不是更容易。

此外,将正确的商品加入sprint的商业可能比确定要删除哪一项更有价值。

关键洞察力:人类操作员正在处理业务现在的优先级,但生产中运行的模型反映了编写时的优先级 - 换句话说,模型具有抓住过去的重点。所以你要小心让模型否决操作员。

更重要的是,您希望了解在从行政人员那里获得的消息时如何获得商业价值,并决定应该在何处管理该责任 - 也许这是一个UI关注点(试图降低高成本)数据输入错误?),而不是域模型问题。