【问题标题】:CQRS: Can the write model consume a read model?CQRS:写模型可以消耗读模型吗?
【发布时间】:2021-06-06 20:10:56
【问题描述】:

在阅读 CQRS 时,经常提到写入模型不应依赖于任何读取模型(假设有一个写入模型和最多 N 个读取模型)。这很有意义,特别是因为读取模型通常只会最终与写入模型保持一致。此外,我们应该能够在不破坏写入模型的情况下更改或替换读取模型。

但是,读取模型可能包含跨写入模型的许多实体聚合的有价值信息。这些聚合甚至可能包含重要的业务规则。可以很容易地想象一个业务策略,它评估读取模型拥有的一条信息,并通过写入模型更改一个或多个实体。但是这个政策应该在哪里定位/实施呢?这不是将来自特定读取模型的信息与写入模型紧密耦合的关键业务逻辑吗?

当我想在不将写入模型与读取模型耦合的情况下实现上述策略时,我可以想象以下策略:在写入模型中包含一个物化视图,该视图会在相关部分同步更新所涉及的实体发生变化(使用 DDD 时,这可以通过域事件来完成)。然而,这将写入模型反规范化,实际上是嵌入在写入模型本身中的特殊读取模型。

我可以想象 DDD 纯粹主义者会说这样的政策不应该存在,因为它代表了一个包含多个实体(又名聚合)的业务不变量/规则。理论上我可能会同意,但在实践中,我还是经常遇到这样的要求。

最后,我的问题很简单:您如何处理根据某些条件更改数据的要求,这些条件的评估需要读取模型?

【问题讨论】:

    标签: domain-driven-design cqrs


    【解决方案1】:

    首先,任何验证命令的写入模型都是读取模型(因为在某些时候验证命令需要读取),尽管它是为验证命令而优化的。所以我不确定你在哪里看到写模型不应该依赖于读模型。

    其次,域事件隐含地是对事件消费者的命令:“处理/考虑/合并此事件”,在这种情况下,写入模型处理器可以订阅来自不同写入模型的事件:从从订阅写入模型的角度来看,这些只是命令。

    【讨论】:

    • 您认为非规范化的写入模型是一种好的做法吗?
    • 我没有看到非规范化写入模型的问题:一旦/如果达到您要单独部署/发展模型的地步,则需要非规范化写入模型写入模型是自治的。
    • 好的,但是为了保持写入模型(无论是否标准化)自主,您不应该将它耦合到任何特定的读取模型吗?
    • 任何命令处理程序都不应该对本身不是命令处理程序一部分的读取模型进行查询:它最终应该只依赖于它接收到的命令。这意味着命令处理模块应该直接从其他命令处理程序接收事件(例如,通过 pubsub 消息传递),或者您有一个自适应过程,它正在查询读取模型并基于它生成命令。
    • 重要的是要注意这两者都是异步的并且最终是一致的。如果您有一个业务规则实际上必须在聚合之间保持高度一致,那么在任何依赖于该业务规则的上下文中,这些都是一个聚合。
    【解决方案2】:

    阅读了很多关于该主题的内容并自己认真思考过,我尝试回答我自己的问题。

    首先,澄清所使用的术语。写入和读取模型自身从不相互依赖。相应的命令和查询组件可能有。因此,我将命令组件及其写入模型的整体称为命令端,将一个特定查询组件及其读取模型的整体称为查询端(其中可能有很多)。

    因此,请考虑一个负责评估和执行业务策略的命令处理程序。它接受一个命令 DTO,对其进行验证,将部分写入模型加载到内存中,并在一个原子事务中对其应用更改。具体的问题是,是否允许此处理程序查询其中一个查询方,以便通知其决定在写入模型中做什么。

    答案将是响亮的NO。原因如下:

    • 命令端将依赖于一个特定的查询端(是否将依赖项隐藏在接口后面并不重要——它仍然存在),因此查询端不能独立更改。
    • 谁真正保证命令处理程序在必要时运行?查询端当然不是负责的,客户端也不是。
    • 执行嵌套查询请求会延长命令请求,这可能会损害性能。

    相反,我们可以执行以下操作:

    • 使用写入模型引发的域事件,在评估策略的命令端注册域事件处理程序。这样就可以保证在需要的时候执行策略。
    • 如果性能允许,此域事件处理程序可以简单地加载所需的写入模型,以评估业务状况。不要过早优化——也许实体很小,很容易加载到内存中。
    • 如果性能不允许,非规范化写入模型并使用域事件维护所需的统计信息。没有人说写入模型本身不能包含面向查询的数据。作为一个写模型只是说它是一个被设计用来写的模型,这也必然包括一些读取的方法。
    • 最后,如果应用策略不是域逻辑本身的一个组成部分,而只是一个用例,请考虑将调用它的责任放到客户端或其他微服务中,首先查询我们的查询端,然后使用适当的参数调用我们的命令端是完全可以的。

    【讨论】:

    • 我必须添加以下内容:命令端的事件处理程序仍然是最终一致的。您有根据陈旧信息做出决定的危险。有一些方法可以解决这种情况,但是使用事件处理程序来“追逐”活动数据库中的当前状态并每秒发生大量写入并不容易。
    猜你喜欢
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    相关资源
    最近更新 更多