Ответ 1
Команды и События могут иметь разные проблемы. Они могут представлять собой технические проблемы, проблемы интеграции, проблемы с доменом...
Я предполагаю, что если вы спросите о домене, вы реализуете модель домена (возможно, даже с помощью Driven Design).
Если это так, я попытаюсь дать вам очень упрощенный ответ, так что вы можете иметь отправную точку:
- Команда: бизнес-намерение, то, что вы хотите, чтобы система сделала. Сохраните определение команд в домене. Технически это просто чистый DTO. Имя команды всегда должно быть обязательным "PlaceOrder", "ApplyDiscount". Одна команда обрабатывается только одним обработчиком команд и может быть отброшена, если она недействительна (однако вы должны сделать все возможное подтверждение перед отправкой команды в ваш домен, чтобы он не может потерпеть неудачу)
- Событие: это то, что произошло в прошлом. Для бизнеса это неизменный факт, который нельзя изменить. Сохраняйте определение события домена в домене. Технически это также объект DTO. Однако название события всегда должно быть в прошлом "OrderPlaced", "DiscountApplied". Обычно событиями являются pub/sub. Один издатель много обработчиков.
Если это так, то обработчики команд/запросов просто реализуются в инфраструктуре?
Обработчики команд семантически похожи на уровень сервиса приложения. Обычно уровень обслуживания приложений отвечает за организацию домена. Он часто строится вокруг случаев использования бизнеса, например, "Размещение заказа". В этих случаях использования вызывают бизнес-логику (которая всегда должна быть инкапсулирована в домене) через совокупные корни, запросы и т.д. Это также хорошее место для обработки проблем с перекрестными ссылками транзакции, проверка, безопасность и т.д.
Однако прикладной уровень не является обязательным. Это зависит от функциональных и технических требований и выбора архитектуры, которая была сделана. Ваша укладка кажется правильной. Я бы лучше сохранил обработчики команд на границе системы. Если не существует надлежащего уровня приложения, обработчик команд может играть роль оркестра. Если вы разместите его в Домене, вы не сможете легко справляться с проблемами перекрестных ссылок. Это компромисс. Вы должны знать о преимуществах и недостатках вашего решения. Он может работать в одном случае, а не в другом.
Что касается обработчиков событий. Я обрабатываю его вообще в
- Уровень приложения, если событие инициирует модификацию другого агрегата в том же ограниченном контексте или если событие вызывает службу инфраструктуры.
- Уровень инфраструктуры, если событие необходимо разделить на несколько потребителей или интегрировать другой ограниченный контекст.
В любом случае вы не должны слепо следовать правилам. Всегда есть компромиссы и различные подходы.
Другой вопрос, откуда вы поднимаете события? Обработчик команд или агрегирование домена?
Я делаю это из корневого агрегата домена. Потому что домен отвечает за повышение событий.
Поскольку всегда существует техническое правило, что вы не должны публиковать события, если была проблема с сохранением изменений в совокупности, и наоборот, я использовал подход, используемый в Event Sourcing, и это прагматично. Мой общий корень имеет коллекцию событий Unpublished
. В реализации моего репозитория я проверил коллекцию событий Unpublished
и передал их промежуточному программному обеспечению, ответственному за публикацию событий. Легко контролировать, что если существует исключение, сохраняющее общий корень, события не публикуются. Некоторые говорят, что это не ответственность репозитория, и я согласен, но кто заботится. Какой выбор. Имея неудобный код для публикации событий, который проникает в ваш домен со всеми проблемами инфраструктуры (транзакция, обработка исключений и т.д.) Или является прагматичным и обрабатывает все на уровне инфраструктуры? Я сделал и то и другое, и поверьте, я предпочитаю быть прагматичным.
Подводя итог, нет единого способа делать вещи. Всегда знайте свои бизнес-потребности и технические требования (масштабируемость, производительность и т.д.). Тогда сделайте свой выбор на основе этого. Я описываю, что я обычно делал в большинстве случаев, и это сработало. Это просто мое мнение.