如何避免在使用 CQRS 的事件源、事件驱动架构中重复类型定义?

How can I avoid repeating type definitions in an event sourced, event-driven architecture with CQRS?

情况

为了更好地理解 CQRS、事件溯源和异步服务通信的概念,我一直在使用 Go、MongoDB 和 RabbitMQ 构建一个小型系统。这包括以下内容:

(我设想为系统中的每个微服务重复一组类似的应用程序,所有这些都通过 RabbitMQ 异步通信)

问题

我觉得我对这些概念有较高的把握,但是在构建这个系统时我 运行 在细节上遇到了一些麻烦。我发现我需要:

  1. 使用 BSON 作为 RabbitMQ 有效载荷使事件发布者的事情变得“简单”——感觉 MongoDB 正在泄漏到设计的其余部分,因为我不会否则选择 BSON

  2. 让事件发布者了解所有事件类型,以便它可以将存储的事件从 BSON 正确转换为 JSON(例如,将日期和 UUID 重写为字符串)以发布到消息总线- 这似乎有点味道,因为需要在不少于 三个 个不同的地方定义各种事件类型(命令端、查询端、 事件发布者)。

问题

  1. 对于使用 CQRS + 事件溯源 + 消息总线的设计来说,这种类型的问题是否正常,或者我的方法存在根本性缺陷?

  2. 如果这是课程的标准配置,以上两个选项中的哪一个更适合在生产环境中使用?

我的搜索没有找到关于这个问题的任何信息,但如果您知道一篇文章或博客 post 解决了这个问题,那可能就足够了。

有事件升级器的概念。事件升级器的目的是将来自事件存储的事件作为 non-typed 数据结构转换为类型化数据结构,然后再发布它们(也在聚合水化之前)。这些通常用于版本控制。请记住,随着系统的发展,您的事件类型发生变化的可能性越来越大,因此您将无法仅从 json/bson.

反序列化

事件输入正确后,在 json 中将它们序列化以将它们传递到总线并在另一端将它们反序列化。

event types would need to be defined in no fewer than three separate places (command side, query side, and event publisher)

只需在共享库中定义您的事件类型。

此外,这无关紧要,但您确实不需要公交车。当涉及到重建投影时,它们会导致更多问题,因为它们不会跟踪上次读取事件。 Greg Young 在 YouTube 的某个地方谈到过它(应该不难找到)。