CQRS中的验证是否必须在UI中单独进行一次,在业务域中进行一次?

sta*_*ica 30 validation dry separation-of-concerns cqrs

我最近阅读了文章CQRSàlaGreg Young,我仍然试图了解CQRS.

我不确定输入验证应该在哪里发生,以及它是否可能发生在两个不同的位置(从而违反了"不重复自己"规则,可能还包括"关注点分离").

鉴于以下应用程序架构:

#      +--------------------+           ||
#      |    event store     |           ||
#      +--------------------+           ||
#           ^          |                ||
#           |  events  |                ||
#           |          v                  
#      +--------------------+         events         +--------------------+
#      |      domain/       | ---------------------> |   (denormalized)   |
#      |  business objects  |                        |  query repository  |
#      +--------------------+           ||           +--------------------+
#         ^   ^   ^   ^   ^             ||                      |
#         |   |   |   |   |             ||                      |
#      +--------------------+           ||                      |
#      |    command bus     |           ||                      |
#      +--------------------+           ||                      |
#                ^                                              |
#                |             +------------------+             |
#                +------------ |  user interface  | <-----------+
#                  commands    +------------------+        UI form data  
Run Code Online (Sandbox Code Playgroud)
  • 域名在命令总线后面的UI中隐藏.也就是说,UI只能向域发送命令,但永远不会直接访问域对象.

  • 当聚合根对某个事件作出反应时,必须不进行验证,但必须更早.

  • 命令被转换为域中的事件(通过聚合根).这是验证可能发生的地方:如果命令无法执行,则不会转换为相应的事件; 相反,(例如)抛出一个异常,它通过命令总线冒泡,返回到UI,然后被捕获.

问题:

如果命令无法执行,我想在UI中禁用相应的按钮或菜单项.但是我怎么知道一个命令在发送之前是否可以执行呢?查询方面在这里不会帮助我,因为它不包含任何业务逻辑; 而我在命令端可以做的就是发送命令.

可能的解决方案:

  • 对于任何命令DoX,引入相应的虚拟命令CanDoX,它实际上不会执行任何操作,但让域提供反馈,命令X是否可以无错误地执行.

  • 在UI中复制一些验证逻辑(真正属于域中).

显然,第二种解决方案不利(由于缺乏关注点分离).但第一个真的更好吗?

sta*_*ica 9

我认为我的问题刚刚被另一篇文章解决, Udi Dahan的Clarified CQRS."命令和验证"部分开头如下:

命令和验证

在思考可能导致命令失败的内容时,出现的一个主题是验证.验证与业务规则的不同之处在于,它声明了与命令无关的上下文事实.命令有效,或者不是.另一方面,业务规则取决于上下文.

[...]即使命令可能有效,仍有理由拒绝它.

因此,可以在客户端上执行验证,检查该命令所需的所有字段是否存在,数字和日期范围是否正常,这类事情.服务器仍将验证所有到达的命令,而不是信任客户端进行验证.

我借此意味着 - 因为我有一个基于任务的用户界面,这是常有建议CQRS运行良好(命令为域动词) - 我永远只能变灰(禁用)按钮或菜单项,如果一个命令不能因为命令所需的某些数据仍然缺失或无效而被发送; 即.UI对命令的有效性本身做出反应,而不是对命令对域对象的未来影响做出反应.

因此,不需要CanDoX命令,也不需要将域验证逻辑泄漏到UI中.然而,UI将具有用于命令验证的一些逻辑.

  • 但我认为您可能仍然需要CanDoX*查询*以使UI中的某些命令变灰. (2认同)