为什么不应将领域事件和事件溯源混淆? – INNOQ


领域事件(Domain Events)与事件溯源(EventSourcing)有什么共同点?名称中都有“事件”一词。但是除此之外,在项目,会议或培训中与架构师和开发人员交谈时,我经常听到领域事件与事件源配合得很好,并且事件源是领域事件的理想来源。在此博客文章中,我想概述为什么我个人不同意这种观点。
在争论为什么我不认同这种观点之前,我想确保对域事件和事件源有足够的了解:


领域事件
在领域驱动的设计中,领域事件被描述为在领域中发生的事情,对领域专家而言很重要。此类事件通常发生,而不管域是否在软件系统中实现或以何种程度实现。它们也独立于技术。因此,领域事件具有高价值的语义,该语义用领域专家所说的语言表达。示例可以是:

  • 用户已注册
  • 已收到订单
  • 付款期限已过

域事件在有界上下文内和跨有界上下文中都是相关的,以实现域内的流程。域事件也理想地适合于通知其他有界上下文有关在自己的有界上下文中发生的特定业务相关事件的信息,从而以事件驱动的方式集成多个有界上下文。

事件溯源
马丁·福勒(Martin Fowler)在其原始博客文章中描述了事件来源的关键特征,如下所示:
事件源确保将对应用程序状态的所有更改存储为一系列事件。
而不是将当前状态直接在数据库中的表中逐字段直接存储在应用程序中,而是在需要时重新加载,然后通过后续更改覆盖,而是按时间顺序排列的事件列表得以保留,然后可用于重建当前事件必要时在内存中显示状态。
事件源是一个通用概念,但通常在与集合有关的领域驱动设计的背景下进行讨论。因此,我将聚合的持久性作为事件源使用的一个示例。
对于事件源的使用,通常列出以下优点:

  • 存储的事件不仅描述了当前状态,而且还描​​述了如何达到此状态。
  • 通过仅重播事件直到特定时间点,可以随时重建过去的任何状态。
  • 可以考虑使用事件源来处理先前事件的不正确处理或延迟事件的到来。

话虽如此,事件源的实施还带来了一定的概念和技术复杂性。事件一旦持久就不应更改,而域逻辑通常会随着时间而发展。因此,代码必须甚至能够处理非常古老的事件。快照是必需的,以便能够以执行方式基于大量事件的历史来重建状态。
此外,例如《欧盟通用数据保护条例》(GDPR)中要求的实施对事件源提出了真正的挑战,因为事件源要求不删除任何持久性事件。

事件源的事件不同于领域事件
那么,为什么我认为这两个概念并不自然地融合在一起?
让我们考虑以下示例:在用于共享自行车的域中,用户想要注册以便租用自行车。当然,还必须为此付费,这是通过使用钱包的预付费方式完成的。
该域的上下文映射的相关部分可能如下所示:

注册过程如下:

  • 用户通过移动应用程序输入他/她的手机号码。
  • 用户收到短信代码以确认电话号码。
  • 用户输入确认码。
  • 用户输入其他详细信息(例如全名或地址)并完成注册。

UserRegistration是有界上下文中聚合实现。UserRegistration在注册过程中,用户多次与聚合中的“他/她”实例进行交互。UserRegistration逐步建立的状态,直到注册成功完成。完成后,用户应该能够为钱包充值并租一辆自行车。

现在,如果使用事件源管理UserRegistration聚合的状态,则会创建以下事件(包含相应的相关状态)并将其保留一段时间:

  1. MobileNumberProvided(MobileNumber)
  2. VerificationCodeGenerated(VerificationCode)
  3. MobileNumberValidated (无其他状态)
  4. UserDetailsProvided(FullName,Address,...)

这些事件足以随时重建UserRegistration聚合的当前状态。不需要其他事件,特别是没有任何事件可以表明注册已完成。一旦UserRegistration聚合中UserDetailsProvided事件被其内部领域逻辑处理,此事实就为聚合所知。因此,一个UserRegistrationcan 实例可以随时回答注册是否已经完成。

此外,每个事件仅包含在重放期间能够重构聚合状态所必需的状态。通常,只有受触发事件的调用影响的状态,即一种“差异”。从事件源的角度来看,将附加状态存储在不受调用影响的事件上是没有意义的。因此,即使显式事件UserRegistrationCompleted得以保留,它也不会包含任何其他状态。

我将事件溯源视为实现状态(例如聚合)持久性的实施策略。此策略不应暴露于集合的边界之外。因此,事件溯源的事件仅应在相应的集合中或在CQRS的上下文中内部使用,以建立相关的读取模型。

另一方面,领域事件表示特定的事实或事件,而该事实或事件是相关的,而与聚合的持久性策略类型无关,例如用于集成有限上下文的持久性策略。
事件源和领域事件当然可以同时使用,但不应互相影响。这两个概念用于不同的目的,因此不应混为一谈。

banq注:事件溯源是有关状态的,领域事件是有关业务领域的,业务领域高于状态,这如图数据表结构高于数据表中数据。先有领域事件,才有是否采取事件溯源的实现,事件溯源偏重技术实现,有一套规范模式,而领域事件则来自与业务领域,与技术有关。