Вариант использования для отображения команд / прикладного уровня: реализация

Некоторые тексты, которые я читал о DDD, указывают на то, что служба приложений или команда (CQRS) на уровне приложений тесно отражает конкретный вариант использования.

Для простых случаев использования это отображение имеет смысл, но в более сложных случаях, когда требуется многократное взаимодействие с пользователем, я пытаюсь понять, как отобразить уровень API-интерфейса, не затрагивая логику приложения, в пользовательский интерфейс.

Пример: - Представьте себе сервис приложений:

ImportProductData(date_source)
  • С точки зрения System / UI, при импорте данных о продукте мы хотим проверить, существует ли какой-либо из продуктов, и если да, то предложить пользователю продолжить или нет, прежде чем продолжить.

Мой обычный подход: расширить API, чтобы включить:

DoesIncludeExistingProducts(data_source)

Если возвращает true, подскажите пользователю, хотят ли они продолжить, затем позвоните.

ImportProductData(date_source, overwrite=True)

Мой вопрос заключается в том, переносит ли это большую часть прикладной логики на уровень пользовательского интерфейса? (т.е. пользовательский интерфейс теперь контролирует, могут ли продукты быть перезаписаны, и нужно ли проверять существующие продукты перед импортом данных продукта и т. д.)

Если это так, я не могу представить, как прикладной и доменный уровни справятся с этим? Помимо:

Вызов:

ImportProductData(date_source)

Если произошел сбой, проверьте причину сбоя, а если из-за того, что продукт уже существует, предложите пользователю и снова позвоните:

ImportProductData(date_source, overwrite=True)

Это похоже на другой способ сделать то же самое, что и выше.

Это может показаться немного педантичным, но я пытаюсь предпринять согласованные усилия, чтобы сделать презентационный слой (MVC) максимально легким и тонким.

Мысли о более элегантных решениях?


2 ответа

Решение

Сначала ознакомьтесь с просветительским постом Джимми Богарда здесь https://jimmybogard.com/domain-command-patterns-validation/. Он не дает ответа на ваш вопрос, но нападает на него так, чтобы вам было легче принять решение.

В этой статье он кратко затрагивает вопрос, который, я считаю, требует большего внимания. Он рекомендует не использовать исключения в качестве механизма связи, если "пользователь часто пытается сделать что-то, что запрещено проверкой моего домена". Используя этот критерий, я предпочитаю разбивать сценарии использования, которые, как ожидается, иногда не срабатывают, на вызов проверки, сопровождаемый вызовом выполнения.

В вашем случае кажется целесообразным иметь запрос проверки (а не команду), такой как IsProductSetValidForImport. В вышеприведенной статье Джимми он пытается решить, насколько богатым должен быть возвращаемый набор ошибок, но предполагается, что возвращаемый набор из запроса будет богатым, поэтому у нас нет проблем. Вы можете вернуть реальную полностью сформированную модель представления для отображения пользователю, вместо того, чтобы пытаться втиснуть достаточно данных в строку ошибки, чтобы закрасить экран. Я предполагаю, что если 3 из 10 продуктов не смогут выполнить импорт, вы можете разрешить пользователю принудительно обновлять некоторые из них, а не другие. Это дает вам такую ​​возможность.

Если этот запрос проверки не возвращает никаких конфликтов, дайте пользователю сообщение "Вы уверены", а затем вызовите API для выполнения команды импорта. Если какое-то существенное состояние изменилось между временем, когда вы вызвали запрос проверки, и временем, когда вы выполнили команду обновления, тогда уместно вызвать исключение и обработать последствия.

Вы не должны обращаться к ApplicationServices, пока пользователь не введет настоящую команду, чтобы сделать что-то, что могло бы потенциально изменить ситуацию.

Что мешает вам иметь слой ViewServices, используемый контроллером в вашем шаблоне презентации MVC для выполнения задач, о которых вы просите?

Другие вопросы по тегам