Bre*_*ias 59 architecture design-patterns command-pattern cqrs
关于命令是否应该具有返回值似乎存在无穷无尽的混淆.我想知道这种混乱是否仅仅是因为参与者没有陈述他们的背景或情况.
以下是混淆的例子......
Udi Dahan说命令"不会向客户端返回错误",但在同一篇文章中他展示了一个图表,其中命令确实将错误返回给客户端.
微软新闻商店文章指出"命令......不会返回响应",但接着提出了一个含糊不清的警告:
随着围绕CQRS的战场经验的增长,一些实践巩固并倾向于成为最佳实践.部分地与我们刚才所说的相反......今天人们普遍认为命令处理程序和应用程序都需要知道事务操作是如何进行的.必须知道结果......
那么,命令处理程序是否返回值?
从Jimmy Bogard的" CQRS神话 "中得到启示,我认为这个问题的答案取决于你所说的程序/语境"象限":
+-------------+-------------------------+-----------------+
| | Real-time, Synchronous | Queued, Async |
+-------------+-------------------------+-----------------+
| Acceptance | Exception/return-value* | <see below> |
| Fulfillment | return-value | n/a |
+-------------+-------------------------+-----------------+
Run Code Online (Sandbox Code Playgroud)
命令"Acceptance"主要指验证.推测验证结果必须与调用者同步,无论命令"履行"是同步还是排队.
但是,似乎许多从业者不会从命令处理程序中启动验证.从我所看到的,它要么是因为(1)他们已经找到了在应用层处理验证的绝妙方法(即ASP.NET MVC控制器通过数据注释检查有效状态)或者(2)架构假设命令被提交给(进程外)总线或队列.后面这些异步形式通常不提供同步验证语义或接口.
简而言之,许多设计人员可能希望命令处理程序将验证结果作为(同步)返回值提供,但它们必须遵守它们使用的异步工具的限制.
关于命令的"履行",发出命令的客户端可能需要知道新创建的记录的scope_identity或者可能需要知道故障信息 - 例如"帐户透支".
在实时设置中,似乎返回值最有意义; 不应使用例外来传达与业务相关的失败结果.但是,在"排队"环境中......返回值自然没有意义.
这是所有困惑可能总结的地方:
许多(大多数?)CQRS从业者假设他们现在或将来会合并异步框架或平台(总线或队列),从而宣称命令处理程序没有返回值.但是,一些从业者无意使用此类事件驱动的构造,因此他们将支持(同步)返回值的命令处理程序.
因此,例如,我相信Jimmy Bogard提供此示例命令界面时会假设同步(请求 - 响应)上下文:
public interface ICommand<out TResult> { }
public interface ICommandHandler<in TCommand, out TResult>
where TCommand : ICommand<TResult>
{
TResult Handle(TCommand command);
}
Run Code Online (Sandbox Code Playgroud)
毕竟,他的Mediatr产品是一种内存工具.考虑到所有这些,我认为Jimmy 小心翼翼地花时间从命令产生void返回的原因并不是因为"命令处理程序不应该有返回值",而是因为他只是希望他的Mediator类具有一致的接口:
public interface IMediator
{
TResponse Request<TResponse>(IQuery<TResponse> query);
TResult Send<TResult>(ICommand<TResult> query); //This is the signature in question.
}
Run Code Online (Sandbox Code Playgroud)
...即使并非所有命令都具有有意义的返回值.
我是否正确地捕捉到为什么这个主题存在混淆?有什么我想念的吗?
Ben*_*ith 16
根据Vladik Khononov 在CQRS中解决复杂性的建议,建议命令处理可以返回与其结果相关的信息.
在不违反任何[CQRS]原则的情况下,命令可以安全地返回以下数据:
- 执行结果:成功或失败;
- 发生故障时出现错误消息或验证错误;
- 汇总的新版本号,如果成功;
此信息将显着改善系统的用户体验,因为:
- 您不必轮询外部源以获取命令执行结果,您可以立即使用它.验证命令和返回错误消息变得微不足道.
- 如果要刷新显示的数据,可以使用聚合的新版本来确定视图模型是否反映执行的命令.不再显示陈旧数据.
Daniel Whittaker主张从包含此信息的命令处理程序返回" common result "对象.
那么,命令处理程序是否返回值?
他们不应返回业务数据,而应仅返回元数据(关于执行命令的成功或失败)。CQRS将CQS提升到更高的水平。即使您违反纯粹主义者的规则并返回某些东西,您还会得到什么?在CQRS中,命令处理程序是的方法,该方法application service加载,aggregate然后在上调用方法,aggregate然后持久化aggregate。命令处理程序的目的是修改aggregate。您将不知道要返回的内容与调用者无关。每个命令处理程序调用者/客户端都想了解有关新状态的其他信息。
如果命令执行被阻止(又名同步),那么您只需要知道命令是否成功执行即可。然后,在更高的层中,将使用最适合您的需求的查询模型查询有关新应用程序状态的确切信息。
否则请考虑,如果您从命令处理程序中返回某些内容,则应承担以下两项责任:1.修改聚合状态; 2.查询某些读取模型。
关于命令验证,至少有两种类型的命令验证:
但是,如果我们在的客户端Presentation layer(即REST端点)中进行了某种级别的提升,Application layer我们可以返回任何内容,并且不会违反规则,因为这些端点是根据用例设计的,因此您确切地知道您想要什么在每种情况下,执行命令后返回。
CQRS 和 CQS 就像微服务和类分解:主要思想是一样的(“倾向于小的内聚模块”),但它们位于不同的语义层次。
CQRS 的重点是使写/读模型分离;诸如特定方法的返回值之类的低级细节完全无关紧要。
请注意以下福勒的报价:
CQRS 引入的变化是将该概念模型拆分为单独的模型以进行更新和显示,在 CommandQuerySeparation 词汇表之后分别将其称为 Command 和 Query。
它是关于模型,而不是方法。
命令处理程序可以返回除读取模型之外的任何内容:状态(成功/失败)、生成的事件(这是命令处理程序的主要目标,顺便说一句:为给定命令生成事件)、错误。命令处理程序经常抛出未经检查的异常,它是命令处理程序输出信号的示例。
此外,该术语的作者 Greg Young 说命令总是同步的(否则,它会变成事件):https : //groups.google.com/forum/#!topic/dddcqrs/xhJHVxDx2pM
格雷格·杨
实际上我说异步命令不存在:) 它实际上是另一个事件。
| 归档时间: |
|
| 查看次数: |
11726 次 |
| 最近记录: |