将事件命名为“CustomerUpdate”
首先让我们从您的活动名称开始。事件的目的是描述已经发生的事情。这与命令不同,命令是为尚未发生的事情发出指令。
您的事件名称“CustomerUpdate”在这方面听起来模棱两可,因为它可能描述过去的某事或未来的某事。
CustomerUpdated会更好,但即便如此,Updated也是另一个模棱两可的术语,并且在业务环境中是非特定的。为什么在这种情况下更新了客户?是因为他们更改了付款细节吗?搬家了?他们是从白银升级到黄金的吗?事件可以根据需要进行具体化。
乍一看,这似乎是多虑了,但是当您从事件有效负载中删除数据和上下文时,事件命名变得特别相关,更多地转向瘦事件(您的问题中的“选项 3”,我将在下面讨论)。
这并不是说在这种粒度级别定义事件总是合适的,只是它是在项目早期向您开放的一条途径,它可能会在以后支付红利(或者可能会让您淹没成千上万的事件类型)。
回到您的实际问题,让我们依次选择您的每个选项:
将事件命名为“CustomerUpdate”并包含有关客户的所有信息(更新与否)
我们将这种“模式”称为Fat消息。
胖消息(也称为快照)表示所描述实体在给定时间点的状态,所有事件上下文都存在于有效负载中。它们很有趣,因为消息本身代表了服务和消费者之间的契约。它们可用于在业务域之间传达状态更改,其中可能希望在消费者处理消息期间存在所有事件上下文。
优点:
- 自我一致 - 可以在不了解其他系统的情况下完全使用。
- 易于使用(更新插入)。
缺点:
- 脆弱 - 服务和消费者之间的契约与消息本身耦合。
- 如果消息以错误的顺序到达,很容易用旧数据覆盖当前数据(提示:您可以通过使用事件源模式来缓解这种情况)
- 大的。
将事件命名为“CustomerUpdate”并仅包含真正已更新的信息
我们称这种模式为Delta消息。
Delta 在许多方面类似于胖消息,尽管它们的生成和使用通常更复杂。JSONPatch标准就是一个很好的例子。
因为它们只是事件实体的部分描述,所以增量还带有一个内置假设,即消费者对所描述的事件有所了解。由于这个原因,它们可能不太适合在事件实体可能不为人所知的业务域之外发送。
当在共享相同实体模型的系统之间同步数据时,Deltas 真的很出色,理想情况下,它们保存在非关系存储(例如,no-sql)中。在这种情况下,可以检索实体,应用增量,然后以最小的努力再次持久化。
优点:
- 小于胖消息
- 涉及共享实体模型的用例中的 Excel
- 可移植(如果基于诸如 jsonpatch 之类的标准,或者在较小程度上基于 diffgram)
缺点:
- 与 Fat 消息类似,假设完全了解数据实体。
- 很容易用旧数据覆盖当前数据。
- 生成和使用复杂(特定用例除外)
将事件命名为“CustomerUpdate”并包含最少信息(标识符)和/或 URI,以让消费者检索有关此客户的信息。
让我们称之为Skinny消息。
Skinny 消息与您定义的其他消息模式不同,因为服务/消费者合同在消息中不再显式,而是暗示在稍后的某个时间消费者将检索事件上下文。这将合约和消息交换解耦,这是一件好事。
这可能适合也可能不适合跨业务领域的事件通信,具体取决于您的企业是如何设置的。因为事件有效负载非常小(通常是带有一些标头的 ID),所以除了事件名称之外没有其他上下文,消费者可以根据该名称做出处理决策;因此,确保正确命名事件变得更加重要,特别是如果消费者可以通过多种方式处理CustomerUpdated消息。
此外,在事件数据中包含实际资源地址可能不是一个好习惯 - 因为事件是已经发生的事情,事件消息通常是不可变的,因此事件中的任何信息都应该永远是真实的,以防事件需要重播。在这种情况下,资源地址很容易过时,并且事件将无法重播。
优点:
- 将服务合同与消息分离。
- 事件名称中包含的有关事件的信息。
- 自然幂等(带时间戳)。
- 一般很小。
- 易于生成和使用。
缺点:
- 消费者必须进行额外的调用以检索事件上下文 - 需要其他系统的明确知识。
- 事件上下文在消费者检索它时可能已经过时,使得这种方法通常不适合某些实时应用程序。
发起事件时,哪种模式最适合?
我认为这个问题的答案是:这取决于很多事情,而且可能没有一个正确的答案。
评论更新:也值得一读,一篇关于消息传递的非常古老、经典的博文:https ://docs.microsoft.com/en-gb/archive/blogs/nickmalik/killing-the-command-message-should-we -use-events-or-documents(也在这里:http: //vanguardea.com/killing-the-command-message-should-we-use-events-or-documents/)