事件源和命令查询责任隔离简介

事件源(ES)命令查询责任隔离(CQRS)的概念已经存在了很长时间。 尽管在.NET方面它们似乎越来越受欢迎,但是它们在Java社区中越来越受到关注。

在过去的几个月中,我在Oasis Digital实施具有这种架构的系统 。 在此过程中,我们的目标是灵活性和进行正确权衡并选择我们自己的工具的能力。 在此过程中提出了一些有趣的解决方案,而使用Axon这样的现有框架可能无法实现。

我将在未来写更多关于这些作品的文章。 在到达那里之前,让我们先简要介绍事件源和命令查询责任隔离。

CQS

命令查询分离(CQS)的主要思想是所有操作都是:

  • 命令,更改系统状态,
  • 查询,从系统中获取一些信息。

一个或另一个,永不都。 例如,如果命令更改了系统中的任何内容,则不应将其用于读取其状态。 无突变的读访问应该总是可能的。 要求系统更改某些内容以读取值似乎是错误的,而无意中更改状态的查询则非常令人困惑,令人惊讶,并且充其量会导致错误。

这些原则可以应用于所有级别。 “干净代码”中的Bob叔叔将其称为良好功能设计的主要原则之一。 该模式也适用于系统设计。

系统架构中的CQRS

命令查询责任隔离(CQRS)是受CQS启发的系统体系结构模式。 它将系统分为两个不同的部分,将用于编写(执行命令)的组件与用于查询的组件分开。 在这样的系统中,我们可以找到与这两个模型相对应的两种请求。

AC代表自治组件

AC代表自治组件

首先,有一些命令 –命令系统执行某些操作或更改其状态。 一条业务逻辑会更新域模型 (或拒绝该命令),并使客户知道更改已被接受(或未接受)。

业务逻辑通常使用域驱动的设计来实现,但它也可以是事务脚本或任何其他适用的技术。 实际上,我们最终在系统的一个区域中混合使用了这两种方法。

每当发生任何变化时,域模型都会以某种方式通知所有人-例如,通过发布域事件。 这些事件由视图模型接收, 视图模型与域模型分开更新它们自己的状态表示。

这导致我们提出第二种请求: 查询 ,从系统获取信息而不更改其状态。 这些仅使用视图模型,而不使用域。

这种模式特别强大的是关注点的分离。

域(写)端与业务有关。 它不关心查询,向用户显示此信息的所有不同方式,性能,用于这些目的的最佳存储等。

另一方面,查询(读取)端仅与读取访问权限有关。 其主要目的是使查询快速便捷。

虽然该域仅实现一次,但是同一数据上可以有多个视图模型。 他们经常使用不同的数据库。 他们甚至可以使用不同的技术-各种NoSQL,规范化和非规范化SQL,内存表示,Lucene索引,OLAP多维数据集等。

读取模型还可以自由使用不同的语言,只要它们使任何事情变得更容易。 在Scala中实现域模型没有任何障碍,但是在Clojure甚至SQL存储过程中进行视图模型。

总体而言,视图模型非常适合(非常安全)进行创新。

与域模型不同,视图模型中的代码质量不一定是完美的。 它们都是关于重塑数据并四处移动以方便读取。 只要不使整个事情难以维持,一些捷径和肮脏的trick俩可能是可以接受的。

读取模型通常会进行非规范化,以最佳方式准备回答具体问题。 它甚至可以像以某种琐碎的键-值方式存储对系统将要处理的每个查询的预先计算集的答案一样极端。

我们通常将视图模型称为“投影”,因为它们将域事件“投影”到特定模型,仅保留必要的信息量,并以最佳形式保存所服务的查询。

注意,所有域逻辑仅在域(写入)模型中实现。 在正确的位置完成一次。 即使直接衍生(计算)值,只要它具有业务意义或使用某种业务逻辑进行计算,它就属于域模型。

活动采购

CQRS常用的另一种模式是事件源

简而言之,这意味着系统中的所有数据都以事件的形式存储在事件日志中。 事件是一条信息,表明发生了某些事情(用户创建,名称更改,添加的送货地址,提交的订单,交付的订单)。 他们总是在过去时,说出事

事件永远不会改变。 您永远不能删除或更新它们。 如果发生了某些事情,那就已经发生了。 如果是错误的话,可以通过产生新的“逆向”事件的补充动作来纠正它,但是没有回头路了,说这没有发生。

结合ES和CQRS

事件源和命令查询责任隔离非常适合。 这是强大的协同效应:由于结合,它们每个都变得更加强大。

当输入命令时,域模型将计算系统的新状态,并可能发出一些新事件(这是更改得以保留的唯一方法)。 当另一个命令进入相同的逻辑区域时,域模型将从过去的事件中恢复,并通过生成一些新事件来响应新命令。 这些事件代表具有业务意义的具体变化。 从技术上讲,它们是系统状态的“增量”(或“差异”)。

视图模型仅处理这些事件,仅拾取它们感兴趣的事件,并更新其状态以支持将来的查询。

好处

使用这种方法有很多好处,让我仅列举其中一些。

CQRS自然会导致基于任务的UI 。 每个动作代表一个非常具体的业务事件。 更改某人的姓名,更改其收货地址或使其成为金牌客户之间可能会有巨大差异。 如果最终用户想更改名称,他们会得到一个小表格,该表格具有该操作所需的内容。 如果他们为客户创造了黄金,那是另一种形式的行动。

将其与传统的CRUD,类似电子表格的系统进行对比。 他们没有“更改名称”或“将客户身份更改为金牌”之类的操作。 用户只能做“更改用户”。 当特定字段突然改变时,实现改变某些东西的逻辑变得更加困难。 验证是一场噩梦。 在不增加顶层复杂性的情况下,审计和仅查看何时发生什么事情以及用户所做的事情是不可能的。

对于用户而言,这也更加困难–用例必须在他们的脑海中实现,他们知道什么时候可以改变以获得预期的效果。

与上述相关,并且CQRS经常与域驱动设计一起使用的原因是,系统的形状自然地映射到业务上下文和用例 。 命令与具体的用户意图相对应,查询旨在回答具体的问题。 再次,这与类似电子表格的数据库前端一样完全相反。

它也适用于更高级别:业务的不同领域(DDD术语中的绑定上下文)可以实现为单独的模型。 例如,仓储上下文可以以与销售上下文完全不同的方式表示一本书。 一个人可能会对它的大小,重量和库存数量感兴趣。 另一个-在作者,类型,封面图像,出版商说明等方面。

事件源还使报告更加容易 。 根据定义,它永远不会丢失信息。 也许昨天您不需要知道用户添加和删除购物车中的商品的频率,而只关心他们最终提交的订单。 但是如今,企业希望跟踪这些信息,因此也许他们可以发现客户想要但改变主意的项目。 在未来的广告中可能值得用这些物品来吸引他们。

回答“传统”系统中的这种变化将是一项不小的努力。 使用ES + CQRS,可能只需要对已有数据进行另一个简单的投影,并立即回答有关过去的问题!

最后,另一个明显的好处是性能 。 由于视图模型是独立的,因此它们可以具有非常不同的架构。 避免联接,使数据保持非规范化,在线性甚至恒定时间内回答许多问题。 只读访问更容易扩展,写侧也不再关心查询。

费用

ES + CQRS并非没有成本,也不是所有系统的最佳方法。 在以后的文章中有更多关于此的内容。

更多资源

就像我一开始所说的那样,这些想法已经存在了很多年。 在线,书籍和会议中都有大量资源可用。 这篇文章仅是表面的介绍,并且仅是(另外)作为该主题的简要介绍。

这里是一些大师的链接:

该帖子还出现在Oasis Digital博客上

翻译自: https://www.javacodegeeks.com/2015/09/introduction-to-event-sourcing-and-command-query-responsibility-segregation.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值