2

我是 DDD 的新手。现在我正在查看域事件。我不确定我是否正确理解了这个领域事件,但我只是在想如果发布的领域事件失败会发生什么?

我这里有个案子。当买家从我的网站订购东西时,首先我们将创建一个对象,Order with line of items。将发布域事件 OrderWasMade 以扣除 Inventory 中的库存。那么情况就是这样,如果在处理事件时,会扣除商品数量,但如果系统尝试扣除库存时,发现该商品没有剩余库存怎么办(金额= 0) . 因此,无法扣除项目金额,但订单已提交。

这种情况会发生吗?

很抱歉在这里挤进了另外两个问题。

  1. 似乎每个事件都在自己的事务范围内,这意味着系统需要一次打开多个到数据库的连接。因此,如果我使用 IIS 服务器,我必须启用 DTC,对吗?

  2. 领域事件和领域服务之间有什么关系吗?

4

3 回答 3

8

领域事件永远不会失败,因为它是对发生的事情的通知(注意过去时)。但是将生成该事件的操作可能会失败并且不会生成该事件。

你告诉我们的场景表明你并不是真的在做 DDD,你是在使用 DDD 词做 CRUD。是的,我知道你是新手,别担心,每个人都误解了 DDD,直到他们得到它(但这可能需要一些时间和大量练习)。

DDD 是关于识别领域模型抽象,而不是代码。代码是您实现该抽象的时候。很明显你没有进行正确的建模,因为领域专家应该告诉你如果产品缺货会发生什么。

接下来,此级别没有 db/acid 事务。这些是实现细节。DDD 的工作方式是确定业务需要在哪里使事物保持一致,这称为聚合

订单已提交,该用例在此停止。当您发布OrderWasMade事件时,会触发另一个用例(扣除库存或其他)。这是一个不同的业务场景,但不是“提交订单”的一部分。如果库存不足,则会发布另一个事件NotEnoughInventory并触发另一个用例。我们在这里跟踪业务,并确定业务为完成订单而执行的每个步骤。

DDD 的艺术在于理解和识别精细的业务功能、涉及的聚合、做出决策的业务行为等,这与数据库或事务无关。

在 DDD 中,聚合是唯一需要使用工作单元的地方。

要回答您的问题:

似乎每个事件都在自己的事务范围内,这意味着系统需要一次打开多个到数据库的连接。因此,如果我使用 IIS 服务器,我必须启用 DTC,对吗?

不,事务、事件和分布式事务是不同的东西。IIS是一个web服务器,我想你想说的是SqlServer。您总是在 Web 应用程序中打开到数据库的多个连接,DTC 与它无关。实际上,这个问题告诉我,您需要阅读更多有关 DDD 的内容,而不仅仅是 Evans 的书。老实说,从 DDD pov 来看,您的要求没有多大意义。您知道 DD 的原则之一:数据库(如持久性细节)不存在。

域事件和域服务之间是否有任何关系

它们都是域的一部分,但它们具有不同的角色:

  • 领域事件告诉世界领域发生了变化
  • 域服务封装了没有自己持久状态的域行为(如计算税)

通常,应用程序服务(充当业务用例的主机)将使用域服务来验证约束或收集更改聚合所需的数据,从而生成一个或多个事件。聚合是持久化的,并且始终以原子方式持久化聚合,即数据库事务/工作单元。

于 2016-03-05T16:23:07.273 回答
2

如果域事件发布失败会发生什么?

MikeSW 已经描述了这一点 - 发布事件(也就是说,使其成为历史的一部分)是与使用事件不同的关注点。

如果当系统尝试扣除库存时,发现该项目没有剩余库存(金额= 0)怎么办?因此,无法扣除项目金额,但订单已提交。

这种情况会发生吗?

所以 DDD 的答案是:询问您的领域专家!

如果您与您的领域专家坐下来,探索无处不在的语言,您可能会发现这是一个很好理解的例外,是有序的快乐路径,具有理解的缓解(“我们将订单的状态标记为待处理,并且我们检查我们是否已经从供应商那里订购了更多库存......”)。这基本上是一个需求发现练习。

当您了解这些要求时,您就去做。

Go do it 通常意味着“传奇”(对该术语的使用有点误导和过度使用);跟踪正在发生的事情的业务流程/工作流/状态机实现。

使用您的示例: OrderWasMade 触发 OrderFulfillment 流程,该流程跟踪订单的“状态”。例如,可能存在“AwaitingInventory”状态,OrderFulfillment 会停在供应商的下一次交货之前。

推荐阅读:

于 2016-03-05T19:12:16.010 回答
1

如果您需要库存始终保持一致,在事件源系统(也可以在非基于事件的系统中,这实际上是正交的)中处理此问题的常用方法是依赖事件存储级别的乐观锁定。

事件基本上有一个修订号,他们希望事件流生效。一旦事件到达持久存储,它的修订号将根据实际流号进行检查,如果它们不匹配,则会引发冲突异常并中止事务。

现在正如@MikeSW 指出的那样,根据您的业务需求,库存检查可以是一个带外过程,以最终一致的方式处理问题。如果流程的另一部分立即接管,最终的范围可以从几毫秒到如果发送一封需要采取人工操作的电子邮件则需要几个小时。

换句话说,如果您的领域需要,您可以选择交易这一系列事件

(OrderAbortedOutOfStock)

为了

(OrderMade, <-- Some amount of time --> OrderAbortedOutOfStock)

最终等于相同的聚合状态

于 2016-03-07T14:27:37.387 回答