用例到命令/应用程序层映射:实施
Use Case to Command / Application Layer Mapping: Implementation
我读过的一些关于 DDD 的文章表明,应用层中的应用服务或命令 (CQRS) 密切反映了特定的用例。
对于简单的用例,这种映射是有意义的,但在需要多个用户交互的更复杂的实例中,我试图了解如何在不推送应用程序的情况下映射 API 的粗粒度级别逻辑进入 UI.
示例:
- 想象一个应用程序服务:
ImportProductData(date_source)
- 从系统/UI的角度来看,在导入产品数据时,我们想检查是否有任何产品已经存在,如果存在,在继续之前提示用户是否愿意继续.
我通常的做法:
扩展 API 以包括:
DoesIncludeExistingProducts(data_source)
如果 returns 为真,提示用户是否要继续,然后调用。
ImportProductData(date_source, overwrite=True)
我的问题是,这是否会将大部分应用程序逻辑移至 UI 层? (即 UI 现在控制是否可以覆盖产品,以及是否应在导入产品数据之前检查现有产品等)
如果是,我无法想象应用层和领域层将如何处理这个问题?除了:
通话中:
ImportProductData(date_source)
如果失败,检查失败的原因,如果是由于产品已经存在,提示用户并再次调用:
ImportProductData(date_source, overwrite=True)
这感觉像是用不同的方式做同样的事情。
这可能看起来有点迂腐,但我正在努力使表示层 (MVC) 尽可能轻薄。
关于更优雅的解决方案的想法?
在用户发出真正的命令来执行可能会改变事情的事情之前,您不应该访问 ApplicationServices。
是什么阻止您在 MVC 表示模式中让控制器使用 ViewServices 层来完成您要求的事情?
首先在此处 https://jimmybogard.com/domain-command-patterns-validation/ 查看 Jimmy Bogards 的启发 post。他没有回答你的问题,而是以一种能让你更容易下定决心的方式来攻击它。
在那篇文章中,他简要地谈到了我认为需要更多关注的一点。如果“用户经常尝试做我的域验证不允许的事情”,他建议不要使用异常作为通信机制。使用此标准,我更愿意将预期有时会失败的用例分解为验证调用,然后是执行调用。
在您的情况下,使用 IsProductSetValidForImport 等验证查询(而非命令)似乎是合适的。在 Jimmy 上面的文章中,他努力决定 returned 错误集应该有多丰富,但是查询中的 return 集应该是丰富的,所以我们没有问题。您可以 return 一个真实的、完全形成的视图模型来显示给用户,而不是试图将足够的数据塞入错误字符串来绘制屏幕。我假设如果 10 个产品中有 3 个导入失败,您可能希望允许用户强制更新某些产品而不是其他产品。这给了你这个机会。
如果这个验证查询 return 没有冲突,给用户一个“你确定”的消息,然后调用 API 来执行导入命令。如果在您调用验证查询和发出更新命令之间偷偷发生了一些重要的状态更改,那么抛出异常并处理影响是合适的。
我读过的一些关于 DDD 的文章表明,应用层中的应用服务或命令 (CQRS) 密切反映了特定的用例。
对于简单的用例,这种映射是有意义的,但在需要多个用户交互的更复杂的实例中,我试图了解如何在不推送应用程序的情况下映射 API 的粗粒度级别逻辑进入 UI.
示例: - 想象一个应用程序服务:
ImportProductData(date_source)
- 从系统/UI的角度来看,在导入产品数据时,我们想检查是否有任何产品已经存在,如果存在,在继续之前提示用户是否愿意继续.
我通常的做法: 扩展 API 以包括:
DoesIncludeExistingProducts(data_source)
如果 returns 为真,提示用户是否要继续,然后调用。
ImportProductData(date_source, overwrite=True)
我的问题是,这是否会将大部分应用程序逻辑移至 UI 层? (即 UI 现在控制是否可以覆盖产品,以及是否应在导入产品数据之前检查现有产品等)
如果是,我无法想象应用层和领域层将如何处理这个问题?除了:
通话中:
ImportProductData(date_source)
如果失败,检查失败的原因,如果是由于产品已经存在,提示用户并再次调用:
ImportProductData(date_source, overwrite=True)
这感觉像是用不同的方式做同样的事情。
这可能看起来有点迂腐,但我正在努力使表示层 (MVC) 尽可能轻薄。
关于更优雅的解决方案的想法?
在用户发出真正的命令来执行可能会改变事情的事情之前,您不应该访问 ApplicationServices。
是什么阻止您在 MVC 表示模式中让控制器使用 ViewServices 层来完成您要求的事情?
首先在此处 https://jimmybogard.com/domain-command-patterns-validation/ 查看 Jimmy Bogards 的启发 post。他没有回答你的问题,而是以一种能让你更容易下定决心的方式来攻击它。
在那篇文章中,他简要地谈到了我认为需要更多关注的一点。如果“用户经常尝试做我的域验证不允许的事情”,他建议不要使用异常作为通信机制。使用此标准,我更愿意将预期有时会失败的用例分解为验证调用,然后是执行调用。
在您的情况下,使用 IsProductSetValidForImport 等验证查询(而非命令)似乎是合适的。在 Jimmy 上面的文章中,他努力决定 returned 错误集应该有多丰富,但是查询中的 return 集应该是丰富的,所以我们没有问题。您可以 return 一个真实的、完全形成的视图模型来显示给用户,而不是试图将足够的数据塞入错误字符串来绘制屏幕。我假设如果 10 个产品中有 3 个导入失败,您可能希望允许用户强制更新某些产品而不是其他产品。这给了你这个机会。
如果这个验证查询 return 没有冲突,给用户一个“你确定”的消息,然后调用 API 来执行导入命令。如果在您调用验证查询和发出更新命令之间偷偷发生了一些重要的状态更改,那么抛出异常并处理影响是合适的。