CQRS 和计算

CQRS and calculations

我目前正在研究一些遵循 CQRS 模式的概念验证代码,但我找不到令人满意的解决方案来解决我[认为]遇到的问题。

系统根据特定场景计算市场变化对给定投资组合的影响。

投资组合可以包含一个到数百个持股,市场场景由用户针对特定请求预先定义或即时定义。

在最简单的形式中,这个问题的解决方案是 returns 一些给定输入值的服务,但在 CQRS 的情况下,在我看来执行计算的部分(域)应该不会被实际 returns 数据(查询)的部分调用。

考虑到像这样的系统很容易有多个投资组合,而且场景的数量也可能非常多,我认为存储计算结果没有意义。

任何人都可以解决这个问题,或者可以指出一篇解决与此类似问题的文章的方向吗?

对我来说,CQRS 的全部意义在于创建两个领域模型。一种针对使用命令更新数据进行了优化,另一种针对使用查询读取数据进行了优化。查询不应该明显地改变系统。将计算结果存储在某种缓存中是查询域模型的一个实现细节。只要缓存及时失效,也就是查询端和命令端最终一致就可以了。你当然应该控制多少 'eventually' 在应用程序中是可以接受的。

当您计算市场变化对投资组合的影响时,您正在对查询域模型执行查询。我没有发现为您感兴趣的场景创建查询类型有问题。

所以,总而言之,我认为您没有问题。请记住,您可以(应该?!)在查询处理程序 and/or 查询域模型中隐藏计算的复杂性。

CQRS 并没有说您应该在写入端预先计算所有内容。当系统的状态通过命令发生变化时,会创建事件,投影会监听这些事件并创建可用于查询的模型。该模型的外观和用途由您决定。如果需要,您甚至可以创建系统的完整第三范式数据库表示的投影。

如果您在读取端进行这些计算更实用,那么我认为这样做没有问题,只要可以丢失计算结果即可。

如果您使用 CQRS 是因为您需要大规模的可伸缩性,而可伸缩性围绕读取这些计算的结果,您将希望将这些预先计算的结果存储在您的读取模型中。

如果 scale/performance 不是主要问题,那么我认为即时计算没有问题。

无论哪种方式,听起来 calculators/calculations 本身都是读取模型的一部分,而不是域模型。听起来 command/write 端将包含一组输入,这些输入将由您的 calculators/calculations.

投影到输出上

仅当需要这些计算的结果来保持不变量时,才需要在写入模型中进行恕我直言的计算。不多也不少

让我们使用(非常简化的)银行域示例: 如果你的不变量声明你不能提取比你在帐户上的更多的钱,那么你应该计算余额(这是该帐户上的取款和存款的总和)并且可能存储它(如果你有某种聚合)以便能够检查取款金额是否大于实际余额,但如果您的系统没有此类不变量,则无需计算,余额很可能只应在系统客户端的读取端计算。

我还想到,您实际上可能会问是否可以使用读取端进行这些计算(如果它们的计算量很大)——这取决于。 大多数人会说,你不应该在写端使用读端,但即使是 Greg Young 也曾说过有时这是可以接受的。 请记住,在写入端使用读取端可能会使您的模型不一致,因为读取端数据可能已过时。