Я не понимаю, где обрабатывать события домена в приложении, основанном на гексагональной архитектуре. Я говорю о событиях внутренней области ограниченного контекста, а не о межконтекстной интеграции / приложениях / публичных событиях.
Фон
Насколько я понимаю, логика приложения (то есть логика сценария использования, логика рабочего процесса, взаимодействие с инфраструктурой и т. Д.) - это то, к чему принадлежат обработчики команд, потому что они специфичны для определенного дизайна приложения и / или дизайна пользовательского интерфейса. Затем обработчики команд вызывают уровень домена, где находится вся логика домена (службы домена, агрегаты, события домена). Уровень домена не должен зависеть от конкретных рабочих процессов приложения и / или дизайна пользовательского интерфейса.
Во многих ресурсах (блогах, книгах) я обнаружил, что люди реализуют обработчики событий домена на уровне приложения, аналогичные обработчикам команд. Это связано с тем, что обработка события домена должна выполняться в отдельной транзакции. И поскольку это может влиять на другие агрегаты, эти агрегаты должны быть сначала загружены через инфраструктуру. Однако ключевой момент заключается в следующем: Событие предметной области разрывается и превращается в серию вызовов методов для агрегатов. Этот важный перевод находится только на прикладном уровне.
Вопрос
Я считаю знание о том, какие события предметной области и какие эффекты влияют на другие агрегаты, является неотъемлемой частью самих знаний предметной области. Если бы я удалил все, кроме уровня домена, разве не следует где-то сохранить эти знания? На мой взгляд, мы должны размещать обработчики событий домена непосредственно на уровне домена:
Это могут быть службы домена, которые получают как событие домена, так и агрегат, на который оно может повлиять, и преобразовывают событие домена в один или несколько вызовов методов.
Это могут быть методы на самих агрегатах, которые напрямую потребляют все событие домена (т. Е. Подпись содержит тип события домена) и делают с ним все, что захотят.
Конечно, чтобы загрузить затронутый агрегат, нам по-прежнему нужен соответствующий обработчик на уровне приложения. Этот обработчик только запускает новую транзакцию, загружает интересующий агрегат и вызывает уровень домена.
Поскольку я никогда нигде не упоминал об этом, мне интересно, не понял ли я что-то не так с DDD, событиями домена или разницей между уровнем приложения и уровнем домена.
РЕДАКТИРОВАТЬ: Примеры
Начнем с этого часто используемого подхода:
// in application layer service (called by adapter)
public void HandleDomainEvent(OrderCreatedDomainEvent event) {
var restaurant = this.restaurantRepository.getByOrderKind(event.kind);
restaurant.prepareMeal(); // Translate the event into a (very different) command - I consider this important business knowledge that now is only in the application layer.
this.mailService.notifyStakeholders();
}
Как насчет этого вместо этого?
// in application layer service (called by adapter)
public void HandleDomainEvent(OrderCreatedDomainEvent event) {
var restaurant = this.restaurantRepository.getByOrderKind(event.kind);
this.restaurantDomainService.HandleDomainEvent(event, restaurant);
this.mailService.notifyStakeholders();
}
// in domain layer handler (called by above)
public void HandleDomainEvent(OrderCreatedDomainEvent event, Restaurant restaurant) {
restaurant.prepareMeal(); // Now this translation knowledge (call it policy) is preserved in only the domain layer.
}