关于命令是否应该具有返回值,似乎存在无尽的困惑。我想知道是否只是因为参与者没有说明他们的背景或情况而引起的困惑。
混乱
这是混乱的例子...
乌迪·达汉(Udi Dahan)说,命令“没有将错误返回给客户端”,但在同一篇文章中,他展示了一个图,其中命令的确向客户端返回了错误。
Microsoft Press Store上的一篇文章指出“命令...不返回响应”,但随后给出了模糊的警告:
随着围绕CQRS的战场经验的增长,一些实践逐渐巩固并趋于成为最佳实践。在某种程度上与我们刚才所说的相反...今天普遍认为,命令处理程序和应用程序都需要知道事务操作的进行方式。结果必须是已知的...
- 吉米·博加德(Jimmy Bogard)说“命令总是有结果”,但随后又花了很多功夫来说明命令如何返回无效。
那么,命令处理程序是否返回值?
答案?
从吉米·博加德(Jimmy Bogard)的“ CQRS神话”中获取线索,我认为该问题的答案取决于您在说什么程序化/上下文“象限”:
+-------------+-------------------------+-----------------+
| | Real-time, Synchronous | Queued, Async |
+-------------+-------------------------+-----------------+
| Acceptance | Exception/return-value* | <see below> |
| Fulfillment | return-value | n/a |
+-------------+-------------------------+-----------------+
验收(例如验证)
命令“接受”主要是指验证。假定验证结果必须同步地提供给调用方,而不管命令“完成”是同步的还是排队的。
但是,似乎许多从业者并不从命令处理程序中启动验证。从我所看到的,这是因为(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);
}
毕竟,他的Mediatr产品是一种内存工具。考虑到所有这些,我认为Jimmy花时间从命令中产生空返回的原因不是因为“命令处理程序不应该具有返回值”,而是因为他只是希望Mediator类具有一致的接口:
public interface IMediator
{
TResponse Request<TResponse>(IQuery<TResponse> query);
TResult Send<TResult>(ICommand<TResult> query); //This is the signature in question.
}
...即使不是所有命令都有返回的有意义的值。
重复并总结
我是否正确地说明了为什么对此主题感到困惑?有什么我想念的吗?
更新(6/2020)
在给出答案的帮助下,我认为我已经消除了混乱。简而言之,如果CQRS命令能够返回指示完成状态的成功/失败,则返回值是有意义的。这包括返回新的数据库行标识,或者返回不读取或返回域模型(业务)内容的任何结果。
我认为“ CQRS命令”混乱的出现超出了“异步”的定义和作用。“基于任务的”异步IO与异步体系结构(例如,基于队列的中间件)之间存在很大差异。在前者中,异步“任务”可以并且将为异步命令提供完成结果。但是,发送到RabbitMQ的命令将不会类似地接收请求/响应完成通知。正是异步架构的后一种上下文导致一些人说“没有异步命令之类的东西”或“命令不返回值”。