CQRS中命令可以返回值吗? -OSKAR


CQRS中通常建议命令的处理要"干净",实际上将其视为“无效函数void”。这种函数不返回任何业务结果,但可以返回操作状态或所需的元数据。
在CQRS中,命令和查询的隔离基于操作行为。查询返回数据,并且不更改应用程序的状态;命令修改状态。这种隔离有助于创建松散耦合的组件,不断发展的解决方案,并通过专注于特定任务,可伸缩性等来减轻程序员的认知负担。
是否有一种用例可以证明从命令处理中返回值是合理的?当然,我们不应该返回任何信息,因为客户端已经知道了他发出的命令。客户端不知道的是在服务器端生成/计算的数据。通常,它这些数据是元数据,例如修改日期,版本,有时还包括业务数据(例如新记录状态)。
我们可以返回更新期间的对象标识符ID,然后,我们可以执行查询命令来获取更新后的数据后,也就是查询需要的读取模型数据。新对象的创建很复杂,除非我们返回客户端生成的标识符ID,否则客户端就不会知道创建了哪个记录。
 
CQRS与API
我们必须记住,我们可以从两个角度看待我们的应用程序:

  • 逻辑-显示我们如何划分和组织业务代码。
  • 技术-描述如何组织特定的实施方式,例如存储结构,部署等。

CQRS代表逻辑视图,API代表技术视图。它们不必相同,我们可能需要将一个概念映射到另一个概念。如果我们正在使用REST API,则在处理了创建新记录的命令之后,我们想返回带有标识符的201状态。如果错误是由业务逻辑引发/返回的,我们希望获得特定的HTTP错误类型。
我们必须做出务实的决定。我认为,CQRS命令返回ID或状态或与我们触发的行为相关的任何其他所需的元数据都是可以的。当然,我们应该小心谨慎,并始终确保需要这种妥协。如果我们滥用它,那么CQRS的关键要素-隔离充其量将是纸面上的契约。
这不仅会影响代码的纯度和耦合性,还会影响性能和可伸缩性。读取模型可以由不同的节点,存储引擎,负载均衡等处理。
我们必须记住,命令本身并没有告诉我们它进行了哪些具体更改。它没有定义将添加,更新还是删除记录。而且,它还不能确定更改是否会影响哪一条记录或更多其他记录。即使是单个更改,也可能涉及刷新几个读取的模型(例如,确认订单会更新用户的订单列表,卖方管理面板,通知视图,订单历史记录等)。所有这些都是由处理命令的业务逻辑定义的,而不是由命令本身定义的。命令代表意图,而不是其处理方式及其产生的影响。
如何使用REST处理CQRS?通常,我尝试将WebAPI合同与命令和查询定义分开。我将WebAPI视为反腐败层。在控制器方法中,我可以生成一个标识符并基于该标识符创建命令。然后,可以将相同的标识符返回到“创建”状态。