关于CQRS的一些问题

时间:2012-08-30 12:12:07

标签: design-patterns orm cqrs maintainability

我目前正在研究是否可以在构建特定系统时应用CQRS并且有一些问题我无法轻易找到答案。

命令可用性/验证

用户可以对特定实体做什么通常不仅与用户的角色有关,而且与特定用户与此实体(例如作者)的关系以及该实体的状态(公共,存档等)有关。

对我来说,似乎CQRS用户操作映射到负责处理它们的命令,但不清楚如何确定哪些操作以及命令可用。

返回每个读取模型的可用命令列表似乎不合适,因为由于需要一致性,我们必须检查仅与用户角色相关的命令(例如,对于菜单项)。

当然,如果另一个用户更改了使命令无效的状态,那么命令必须在事务中再次进行验证。

对要求变更的抵制

根据我的经验,维护一个具有详细逻辑和太多类/表绑定到特定业务对象的系统是一场噩梦。

在CQRS中,某个特定业务实体可能有多个读取模型。当需要更改该实体时,也应修改所有相关的读取模型。

为了可维护性,有必要以某种方式使它们相关,这在重构时很容易显现。

在相关的说明中,有很多过于具体的命令也会导致可维护性问题 - 我认为每个用例的一个命令应该最好吗?我是正确的吗?

读取不修改域模型的模型和命令

在CQRS命令中应该更新读取模型,用户可以在此期间访问它的旧版本。

在我看来,有两个特殊情况会导致问题。

首先,有些命令不会修改域模型本身(可能只是状态),而是执行涉及第三方系统/框架/电子邮件等的某些操作,在某些情况下,这些命令可以采取跑了很多时间。

正如我在这里看到的,我们需要一个将域模型与命令执行状态相结合的读取模型。此读取模型可用作当前正在处理的项目的历史记录或列表。

第二个某些命令产生结果。当命令成功完成时,需要为用户显示此结果,并且在某些情况下必须在一段时间后丢弃甚至是文件。因此,必须有一种方法将这些命令的结果存储在数据库中,并将它们与特定的命令实例相关联。换句话说,有一个临时阅读模型。

读取模型表与内存中缓存

另外,我认为,使用二级ORM缓存(对于查询结果),没有必要为读取模型提供数据库表,但是ORM可以在第一次执行查询时生成它们,缓存结果并在更改模型实体时自动使它们无效。这种方法似乎是一个很好的起点,可以强制执行CQRS接口/模式但可以更改,并且奖励可以支持动态预测(当用户选择要查看的列等时)。

1 个答案:

答案 0 :(得分:4)

总的来说,我不确定你提出的具体问题,所以我正在尽力回答这些问题。我希望这有帮助。如果我错过了你的问题,我会澄清 - 请告诉我。

命令可用性/验证

我不确定您对此部分的问题是什么,但实质上您的用户行为会驱动您可用的命令。命令对于该特定用户是否有效可以由提交命令的UI控制器(或任何机制)处理,或者可以由接收命令的域处理。该命令应该包含足够的信息供域进行评估,然后更改其状态并引发事件。

抵制需求变更

如果实体发生变化,并非所有相关的阅读模型都需要更改 - 它实际上取决于阅读模型的目的。维护读取模型的一些方法可以是为每个相关的读取模型集使用不同的模式,或使用命名标准(例如ORDER_xxx)。我更喜欢前者,因为这更清洁(至少从我的观点来看)。

阅读不修改域模型的模型和命令

命令并不总是应该更新读取模型。如果域中的业务规则引发了处理和持久化的相应事件,则可以更新读取模型。仅仅因为发出命令并不意味着将更新读取模型。

如果您遵循CQS(和CQRS),那么您的命令不应返回结果。命令返回void。命令是你告诉系统做某事。您所描述的是一个两步过程:发出命令然后发出读取请求。读取请求很可能会产生“旧”数据(意味着,在命令更新读取模型之前)。有几种方法可以解决这个问题。你可以轮询 - 不是一个非常优雅的方式,但它的工作原理。发出命令后,您可以将用户带到中间页面(“感谢您的订单,是否要订购其他东西?”)然后当用户返回时,他们会看到他们的更新列表(因为命令有现已处理)。再次,不理想。但这是最终一致性的本质。没有真正的答案 - 它实际上是由用户与系统交互的方式驱动的。

对于刚刚更新状态或与第三方系统交互的命令,如果没有用户等待它们完成,这些命令是否不能脱机完成?我认为这是让您的系统反映用户将如何使用系统的另一种情况。

读取模型表与内存缓存

如果你问这是不是一个好主意,我不太确定。这个内存缓存的起点是什么?系统重启后会发生什么 - 您的模型会发生什么?你重建它,从哪里以及如何恢复状态?您是否正在使用事件采购,并且您将重播上一个快照中的所有事件以使您的域模型到位?

在不知道这些问题的答案的情况下,我无法给出答案。