4

考虑到领域事件模式和这篇文章,为什么人们建议每个事务模型保留一个聚合?当一个聚合可以改变另一个聚合的状态时,有很好的例子。即使通过删除聚合(或更改其身份)也会导致更改引用它的其他聚合的状态。有人说每个聚合保留一个事务有助于可伸缩性(每个服务器保留一个聚合)。但是这种思维方式不是打破了 DDD 的基本特征:技术不可知论吗?

因此,根据上面的陈述和您的经验,设计聚合、领域事件是否会导致其他聚合发生变化,这将导致每个交易有 2 个或更多聚合(例如:下新订单时)有 100 个项目将客户的状态从正常更改为 VIP )?

4

2 回答 2

6

这里有几件事在起作用,甚至需要做出更多的权衡。

  • 首先,你是对的,你应该首先考虑模型。毕竟,语言、模型和领域的相互作用是我们做这一切的目的:提出精心设计的抽象作为问题的解决方案。
  • 战术模式——来自 DDD 书——是达到目的的一种手段。在这方面,我们不应该过分强调它们,尽管它们对我们很有帮助(并且给其他人带来了很大的麻烦)。它们帮助我们在模型中找到“一致性单元”、一起改变的事物、事务边界。恐怕这就是问题所在。当某事发生时和它发生的副作用何时应该是可见的是两件不同的事情。然而,它们常常被视为一体,从而导致这种不舒服的感觉,我们的反应是试图在边界内挤压一切,而不加质疑。尽管如此,我们还是留下了那种不舒服的感觉。有很多事情在逻辑上可以被视为“整体变化”,而在物理上则有多个小变化。这需要技巧和经验,甚至直言不讳地试图知道什么时候会出现这种情况。请注意,并非所有事情都可以通过这种方式解决。
  • 扩大规模还是不扩大规模,这通常是个问题。如果您不需要扩展,将东西放在一个盒子上,满足于某种备份/恢复策略,您可以改变规则并一次性影响多个聚合。但是你必须意识到你正在这样做,而不是把它当作既定的,因为不可避免地会发生变化,它可能会扰乱这种特殊的处理方式。所以,公平的警告。更微妙的是为什么你要一次更改多个聚合的问题。人们经常用“你的总边界错误”的答案来回应这个问题。实际上,这意味着您需要进行更多的领域和模型探索,以发现这些同步、多聚合更改的真正动机。通常,UI 或服务是具有这种“不合理”期望的。但可能还有其他原因,可能只需要一组不同的抽象来解决相同的问题。这是 DDD 的一个非常重要的方面。
  • 您给出的示例似乎我可以将其作为两个单独的交易处理:下订单,作为对此的反应,因为下订单时包含 100 件商品,所以客户被设为 VIP。正如 MikeSW 在他的回答中暗示的那样(我在他发布他的帖子后开始写我的),问题是何时、谁、如何以及为什么应该观察这种客户状态的变化。基本上,“下一个”行为决定了先前行为的一致性要求。
于 2014-04-27T18:19:04.423 回答
2

聚合对相关的业务对象进行分组,而聚合(AR) 是该聚合的“代表”。AR 本身是对(更大、更复杂)领域概念进行建模的实体。在 DDD 中,模型总是相对于上下文(有界上下文 - BC),即该模型仅在该 BC 中有效。

这允许您定义一个代表特定业务上下文的模型,并且您不需要将所有内容都放在一个模型中。订单在一种情况下是 AR,而在另一种情况下只是 id。

由于 AR 几乎封装了所有较低的概念和业务规则,因此它作为一个整体发挥作用,即作为一个事务/工作单元。存储库始终与 AR 一起使用,因为 1) 存储库始终处理业务对象,并且 2) AR 代表给定上下文的业务对象。

当您有一个涉及 2 个或更多 AR 的用例时,业务工作流程和该用例的正确建模至关重要。在很多情况下,这些 AR 可以独立修改(一个人不关心其他人),或者 AR其他 AR 行为而改变。

在您的示例中,这非常简单:当客户订购 100 件商品时,会生成并发布一个域事件。然后你有一个处理程序,它将检查订单是否符合客户促销规则,如果符合,则会发出一个命令,结果会将客户状态更改为 VIP。

领域事件非常强大,允许您在最终一致的环境中实现事务。旧的 db 事务是一个实现细节,通常在持久化一个 AR 时使用(记住 AR 被视为一个逻辑单元,但持久化一个可能涉及多个表,因此是 db 事务)。

最终一致性是领域事件的“特征”,它自然适合丰富的领域(实际上是现实世界)。在某些情况下,您可能需要即时一致性,但这些是特殊情况,它们与 UI 相关,而不是域的工作方式。当然,它确实取决于一个域到另一个域。在您的示例中,客户不会介意在下订单后 2 秒或 2 分钟而不是同一毫秒成为 VIP。

于 2014-04-27T17:44:55.523 回答