我正在学习什么是CQRS模式,并且知道还有CQS模式。
当我尝试搜索时,我发现了很多关于CQRS的图表和信息,但没有找到很多关于CQS的信息。
CQRS模式的关键点
在 CQRS 中,有一个模型可写(命令模型)和一个模型可读(查询模型),它们是完全分开的。
CQS 与 CQRS 有何不同?
我正在学习什么是CQRS模式,并且知道还有CQS模式。
当我尝试搜索时,我发现了很多关于CQRS的图表和信息,但没有找到很多关于CQS的信息。
在 CQRS 中,有一个模型可写(命令模型)和一个模型可读(查询模型),它们是完全分开的。
CQS 与 CQRS 有何不同?
CQS(命令查询分离)和CQRS(命令查询职责分离)非常相关。您可以将 CQS 视为处于类或组件级别,而 CQRS 更多地处于有界上下文级别。
我倾向于认为 CQS 是微观层面的,而 CQRS 是宏观层面的。
CQS 规定了用于查询或写入模型的单独方法:查询不会改变状态,而命令会改变状态但没有返回值。它是由 Bertrand Meyer 设计的,是他在 Eiffel 编程语言方面的开创性工作的一部分。
CQRS 规定了类似的方法,除了它更多的是通过您的系统的路径。查询请求采用与命令不同的路径。查询返回数据而不改变底层系统;该命令更改系统但不返回数据。
几年前, Greg Young对 CQRS 是什么进行了相当详尽的描述,并深入探讨了 CQRS 如何是 CQS 的演变。这份文档在几年前向我介绍了 CQRS,我发现它仍然是一个非常有用的参考文档。
这是一个老问题,但我会尝试回答它。我不经常在 StackOverflow 上回答问题,所以如果我在链接到事物、写长答案等方面做了超出社区范围的事情,请原谅我。
CQRS 和 CQS 之间有很多区别,但是 CQRS在其定义中使用CQS!让我们从定义两者开始,然后我们可以讨论差异。
CQS根据返回值定义了两种类型的消息:无返回值(void)指定这是一个Command;返回值(非 void)指定此方法是 Query。
命令改变状态。查询没有。
现在是 CQRS,它使用与 CQS 相同的定义来表示命令和查询。CQRS 说的是我们不想要一个具有 Command 和 Query 方法的对象。相反,我们想要两个对象:一个包含所有命令,一个包含所有查询。
总体思路很简单;做完这件事后,事情变得有趣了。网上有很多讨论,我讨论了一些相关的属性(对不起,在这里输入太多了!)。
我发现人们经常说他们在有 CQS 时会练习 CQRS。
最大的区别是 CQRS 对命令和查询使用单独的数据存储。查询存储可以使用不同的技术,如文档数据库,或者只是同一数据库中的非规范化模式,这使得查询数据更容易。
数据库之间的数据通常使用服务总线之类的东西异步复制。因此,查询存储中的数据最终是一致的(将在某个时间点存在)。应用程序需要考虑到这一点。虽然可以使用相同的事务(相同的数据库或两阶段提交)在两个存储中写入,但出于可伸缩性的原因通常不建议这样做。
CQS 架构从相同的数据存储/表读取和写入。
阅读发明者 Greg Young 的回答
我认为,就像“依赖注入”一样,这些概念非常简单,并且被认为是理所当然的,以至于它们具有花哨的名称这一事实似乎驱使人们认为它们比实际更重要,特别是因为 CQRS 经常与事件溯源一起被引用。
CQS 是读取到改变状态的方法的分离;不要在一个方法中同时做这两个。这是微观层面。
CQRS 将此概念扩展到更高级别的机器-机器 API、消息模型和处理路径的分离。
因此,CQRS 是您应用于 API 或外观中的代码的原则。
我发现 CQRS 本质上是 SOLID 中非常强大的 S,将这种分离深入到开发人员的心灵中,以生成更可维护的代码。
我认为 Web 应用程序不适合 CQRS,因为通过表示传输的状态突变意味着命令和查询是同一请求-响应的两个方面。表示是命令,响应是查询。
例如,您发送订单并接收所有订单的视图。
想象一下,如果将网站的代码分解为命令端和查询端。路由操作处理代码需要属于这些方面之一,但它两者兼而有之。
想象一个更强的隔离,如果代码被移动到两个不同的可编译代码库中,那么网站将接受表单的 POST,但用户必须浏览到另一个网站 URL 才能看到操作的影响。这显然是疯了。一种解决方法是始终重定向,尽管这并不是真正的 RESTful,因为理想的 REST 应用程序是下一个表示包含超文本以驱动下一个状态转换等等。
鉴于网站是人与机器(或机器与机器)之间的 REST API,这也包括 REST API,尽管其他类型的 HTTP 消息传递 API 可能非常适合 CQRS。
网站范围内的服务或外观显然可以很好地与 CQRS 配合使用,尽管操作处理程序将位于此边界之外。