避免在领域驱动设计中使用工作单元模式。

26

我已阅读此内容,这让我三思...

"避免使用工作单元模式。聚合根应该定义事务边界。"

为什么在应用领域驱动设计时应该避免使用工作单元模式?

3个回答

34

在我发帖之前,我建议先阅读V. Vernon的《实现领域驱动设计》书中的这一章。它可以帮助你更好地了解聚合,并对你的问题有详细的回答。

在一个正确设计的系统中,每个命令只会改变一个聚合,每个聚合都有由聚合根中的不变量定义的边界。因此,当您对聚合进行任何更改时,会检查不变量并在一个事务中应用(或不应用)更改。这是“事务一致性”。在这里需要使用工作单元吗?我认为不需要。

但很多时候我们会遇到需要同时更改多个聚合的情况。事务变得更大,它们涉及系统的多个部分,我们谈论的是“最终一致性”。在这种情况下,UoW是一个很好的助手。

由于没有上下文,很难猜测作者的想法,但我认为他提到了事务一致性的情况。在分布式系统中,您需要使用类似于UoW的东西来为系统提供最终一致性。


2
在他关于聚合设计的论文中,弗农提到UoW作为管理事务一致性的方式之一(http://dddcommunity.org/library/vernon_2011 - 参见第4页第1部分的脚注)。对我来说,“避免使用工作单元模式”似乎是一个奇怪的建议 - 这是对弗农方法的误解吗? - guillaume31
旧答案,但在CQRS+ES实现中,在聚合体内使用事务的一个非常有效的用途是发布事件。 例如,为了达到最终一致性状态,不仅应该完成命令,而且通过使用任何发布机制来持久化事件。如果无法发布/分派事件,则无法实现一致性。即使没有使用ES,它也不会明确损害任何东西-只要不用于跨聚合边界,例如使单个命令更改多个聚合的过渡状态。 - Joseph Ferris
聚合根是以数据库为中心的,定义了事务的范围。然而,在现代分布式系统中,工作单元可以表示对以下操作的ACID操作:保存聚合、发送命令、发出事件。也就是说,拥有一个工作单元是至关重要的。 - Serge Semenov
2
@SergeSemenov Aggregates是如何以数据库为中心而不是领域为中心的? - Gabriel
嗨,我在我的系统中遇到了是否使用UoW的决定。我可以看出,如果开发人员不熟悉DDD,引入UoW的一个缺点是会让他们感到困惑。作为一个非常新手的DDD,对于我的领域中哪些实体是聚合根一直不太清楚。当使用UoW时,很容易在多个实体(不是聚合)上进行事务处理,因为它们似乎保证了相关实体之间的一致性。然而,如果这些实体属于一个聚合,这在第一次就不应该是必要的,正如你所提到的那样。 - aIKid
显示剩余2条评论

7
基本上,根据M. Fowler所说,UoW只是一个智能持久化工具(无论这个任务有多复杂)。因此,在我看来,与DDD方法没有固有的不兼容性,它提供的指导更多地关于你的领域建模的“精神”而不是技术工具。
没有上下文,很难知道引文作者在想什么;但也许他写这篇文章是因为当使用UoW时,通常很难使实体管理自己的生命周期(以及其他实体),通常涉及持久性和事务行为。
事实上,可以在DDD风格的应用程序中使用UoW模式AOP。通过这种类型的工具,可以保持DDD精神,具有以实体为中心、业务可用的领域模型,同时利用复杂但业务正交机制来实现适当的事务持久性。
通常,在Java世界中,您可以在DDD应用程序中使用:

这些提供了准备好DDD(和大量注释的;])实体。


3
首先,聚合是一个对象,用于保存一组可加载实体,以便应用于命令。
- 实体可以属于许多不同的聚合。 - 每个命令只能与一个聚合对话,该聚合应该具有命令所需的所有实体。 - 聚合可以在多个命令之间重复使用。
“工作单元”基本上是一个即时聚合,允许对一组实体进行单个事务更新,而无需在代码中明确定义聚合来执行此操作。
这样做的代价是没有显式的聚合类可以放置维护不变量的突变方法。
顶级投票答案包含:
在一个正确设计的系统中,每个命令一次只更改一个聚合,每个聚合都有边界,其由聚合根中的不变量定义...
但很常见我们处于需要同时更改一个以上的聚合的情况。事务变得更大,它们触及系统的多个部分,我们谈论的是最终一致性。在这种情况下,UoW是一个好帮手。
这是荒谬的,因为按定义,聚合就是事务所需的一堆东西。如果你发现自己“需要来自两个不同聚合的实体”,那么你实际上需要“定义一个额外的聚合,它保存了所需的实体引用”。
我认为答案试图表达的是:“很常见我们处于需要同时更改两个不同存储器上的数据,由于无法在单个事务中更新它们而无法添加到单个聚合中。事务变得更大,它们触及系统的多个部分,我们谈论的是最终一致性。在这种情况下,UoW是一个好帮手。”

你正在混淆聚合和聚合根。 - Not Important
我不认为我是。 - mcintyre321
是的,您可以创建TransferMoneyAggregate(或甚至是TwoAccountEntities聚合,呃)并使用足够(乐观地)锁定的数据为命令提供支持。有趣的是,当您惰性加载两个实体时,ORM与工作单位实际上正在即时执行此操作。 - mcintyre321
ORM与UoW的缺点是它会移除Repositories上手写的Save(一些聚合对象)方法,因此在持久化时只能使用ORM映射数据库中的数据。例如,自定义的Save方法可以将二进制大对象写入S3,然后再写入一个带有该对象ID的数据库条目。 - mcintyre321
哈哈,“TransferMoneyAggregate”是你的名字,不是我的!“EntitiesRequiredForAMoneyTransferAggregate”,“TwoAccountsAggregate”或者其他你喜欢的名字都可以。 - mcintyre321
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接