事件溯源:将业务逻辑放在哪里

Event Sourcing: where to put business logic

我可以想到在事件源系统中放置域逻辑的两个地方,任何一个都有缺点。

示例:根据一些数据计算指标。
要么我必须计算两次度量(一次在域模型中,一次在投影中)
或者我必须在发送事件并将其包含在那里之前计算它。

我想你的聚合根中有一些状态。这应该包含有关您的业务的逻辑。所以它应该有足够的数据来创建基于命令的事件。
此事件的消费者(查询模型)进行计算。因此,如果目的是计算平均值,它必须设法以给定的方式存储自己。
我做了类似的事情。曾经是业务逻辑的一部分,所以在聚合中,曾经在查询模型中,因为它不是业务逻辑的一部分,更多的是度量计算。
不要害怕将数据存储在多个地方。一致性的责任应该委托给事件分发,而不是您的业务逻辑。

控制流程通常是这样的:

  • 命令被发送到命令处理程序并且命令中的属性被预先验证,例如身份指向现有实体并且所有强制信息都存在并且格式正确
  • 命令处理程序从存储库中检索聚合(通过读取事件流,但这并不重要)并根据此命令需要完成的操作调用聚合方法
  • 聚合方法必须确保它们的参数和聚合状态相互允许执行操作。

  • 聚合方法然后创建一个事件并调用此WhenApply方法来处理事件

  • 事件处理程序改变聚合状态,那里没有逻辑!

  • 然后控制流返回到命令处理程序,并且它将所有新事件保存在存储区中

进一步的行动与预测有关。

在应用事件之前将不变保护(即业务逻辑)放入聚合事件中的原因是因为当事件生成时就没有回头路可走了。这件事已经发生了。您不能拒绝申请一个事件。考虑在从事件流(从存储库读取)中恢复聚合时重播事件,如果有一天您决定在那里有一个 if-throw 组合,这将如何工作?

所以,简而言之:

  • 发送命令前应用初始逻辑
  • 命令处理程序中有一些额外的逻辑
  • 聚合方法中的聚合保护(很可能也在命令处理程序中)
  • 事件处理程序中没有逻辑,只有状态变化

没有人说过事件溯源可以帮助您解决计算中的问题。为了建立额外的安全网,您可能想要保存命令,但随后您将不得不发出补偿事件或截断流,这并不是您真正想要做的。