该规则应该是每个聚合的一个交易"在对域进行建模时要考虑到什么?

时间:2014-04-27 14:37:51

标签: oop transactions domain-driven-design domain-events command-query-separation

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

因此,基于上述陈述和您的经验,设计聚合,域事件导致其他聚合更改是不好的,这将导致每个事务有2个或更多聚合(例如:当新的时候下订单有100个项目将客户的状态从正常更改为VIP)?

2 个答案:

答案 0 :(得分:6)

这里有几件事情可以做,甚至可以做出更多的权衡。

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

答案 1 :(得分:2)

聚合组相关的业务对象,而聚合 root (AR)是'代表'那个聚合。 AR本身是一个模拟(更大,更复杂)域概念的实体。在DDD中,模型总是相对于上下文(有界上下文 - BC),即该模型仅在该BC中有效。

这允许您定义代表特定业务环境的模型,并且您不需要仅在一个模型中推送所有内容。 订单在一个上下文中是AR,而在另一个上下文中只是一个ID。

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

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

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

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

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