Должны ли агрегаты быть обработчиками событий

В настоящее время я начинаю свою первую настоящую попытку создания системы DDD / CQRS / ES после изучения большого количества материала и примеров.

1) Я видел примеры источников событий, в которых агрегаты являются обработчиками событий, а их метод Handle для каждого события - это то, что изменяет состояние экземпляра объекта (они реализуют интерфейс IHandleEvent ‹EventType› для событий, которые могут изменять состояние)

2) Я также видел примеры, в которых агрегаты выглядели бы как простые классические классы сущностей, моделирующие предметную область. Другой класс обработчика событий участвует в изменении состояния.

Конечно, состояние изменяется на агрегате обработчиками событий в обоих случаях при перестроении агрегата из вызова репозитория, который получает все предыдущие события для этого агрегата, и когда обработчик команд вызывает методы агрегата. Хотя в последнем я видел примеры, когда события публикуются в обработчике команд, а не в агрегате, что, как я убежден, неверно.

Мой вопрос в том, каковы плюсы и минусы между методом (1) и (2).


person Mark Kennedy    schedule 11.11.2014    source источник
comment
Интересно, как выглядит поток выполнения в подходе 2). Как отдельный обработчик событий меняет состояние в агрегате? Вам нужно подвергнуть это все государство? Это делается с помощью метода на Агрегате? Каким должно быть имя такого метода, а не имя метода, который вызывается обработчиком команд и генерирует событие? Разве это не надумано?   -  person guillaume31    schedule 12.11.2014
comment
При дальнейшем рассмотрении примера кода для 2 и того, что, как я думал, он делает, я пришел к выводу, что это очень странный подход и, как вы говорите, надуманный и чрезмерно спроектированный. Я чувствую, что должен отредактировать вопрос, чтобы просто спросить, является ли подход (1) обычным подходом для шаблона поиска событий с агрегатами или есть другой способ, с которым я не сталкивался? (однако нет необходимости обсуждать моментальный снимок, поскольку я чувствую, что понимаю его место, когда оно требуется)   -  person Mark Kennedy    schedule 12.11.2014
comment
До сих пор я видел только метод 1) с функциональными вариантами, в которых часть поведения обработчика команд переходит в сам агрегат.   -  person guillaume31    schedule 12.11.2014


Ответы (2)


Работа по получению / обработке команды отличается от ее выполнения. Подход, который я использую, - иметь обработчика. Его работа - получить команду. Команда содержит AggregateId, который затем может использовать для получения всех событий для агрегата. Затем он может применить эти события к агрегату с помощью метода LoadFromHistory. Это обновляет агрегат и делает его готовым к приему команды. Итак, моя короткая версия - это вариант 2.

У меня есть несколько сообщений, которые вы сочтете полезными, первая - это обзор типичного приложения CQRS / ES. Это не так, как должно быть, просто как они часто бывают. Вы можете найти это на странице CQRS - пошаговое руководство по поток типичного приложения!

У меня также есть сообщение о том, как создать совокупный корень для CQRS и ES, если это полезно. Вы можете найти это на странице Aggregate Root - How to build One for CQRS and Event Sourcing

В любом случае, я надеюсь, что это поможет. Всего наилучшего, создавая ваше приложение CQRS / ES!

person Codescribler    schedule 15.11.2014
comment
Выбрал это в качестве ответа, поскольку информация и пример в вашем сообщении в блоге были очень всеобъемлющими и легкими для понимания. Я также согласен с тем, что пример Грега Янга лучше всего подходит для тех, кто пытается изучить источники событий и cqrs. Единственный комментарий и изменение, которые я бы лично предложил, - это не передавать фактический объект команды в агрегированный объект, а вместо этого извлекать данные из команды в обработчике и передавать их в метод, представляющий поведение домена. В этом смысле я согласен с MikeSW, что это в основном деталь реализации. Также Codescribler, весь ваш блог великолепен! - person Mark Kennedy; 16.11.2014
comment
... но вариант 2 из вопроса касается отдельного обработчика событий для изменения состояния, а не обработчика команд для обработки входящих команд, верно? @Codescribler, я не понимаю, как ваш (разумный) рекомендуемый подход соотносится с вариантом 2. - person guillaume31; 17.11.2014
comment
На самом деле гийом прямо здесь, то, что я бы сказал в ответе, - это вариант 1 без наличия интерфейсов IHandle в агрегате (так что агрегат не является зарегистрированным обработчиком событий, события просто применяются внутри для изменения состояния). То, что я описал в варианте 2, мне кажется неправильным. Возможно, для большей ясности удалите ссылку на вариант 2 в ответе. - person Mark Kennedy; 18.11.2014
comment
Чтобы было ясно, IHandle находится не в агрегате, а в обработчике команд (доменная служба). Он отвечает за то, чтобы исторические события применялись к агрегату перед выдачей команды. В случае успеха агрегат генерирует событие (я) и применяет его / их к себе. Затем обработчик команд получает все изменения и сохраняет их. Это вариант 3? - person Codescribler; 18.11.2014
comment
Хорошая статья! Однако я бы сделал это немного иначе: сохранил бы агрегат в чистоте и заставил бы обработчик команд применять сгенерированные новые события к агрегату. - person Constantin Galbenu; 21.09.2016

Я согласен с Codescribler, но мне нужно углубиться в детали. ES - это выражение состояния объекта в виде потока событий (которые будут сохранены). Обработчик сообщений - это просто реализация службы, которая сообщает Entity, что делать.

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

Но ... в недавнем приложении из прагматических соображений моя сущность ES принимала команды напрямую, хотя сама сущность не была реализацией обработчика команд. Обработчик просто передаст команду объекту.

Итак, вы действительно можете обрабатывать сообщения напрямую с помощью объекта, но только в качестве детали реализации, я бы не рекомендовал назначать объект как обработчик команды / события, поскольку это нарушение разделения проблем.

person MikeSW    schedule 15.11.2014
comment
Если объект не является обработчиком команд, как объект / агрегат генерирует события? В ответ на что? - person Constantin Galbenu; 21.09.2016
comment
Я реализую службы приложений как обработчики команд, агрегат генерирует события в ответ на метод, вызываемый службой приложения. - person MikeSW; 21.09.2016
comment
Почему эта делегация? Что еще нужно сделать службе приложения перед вызовом метода на агрегате? - person Constantin Galbenu; 22.09.2016
comment
Я писал об этом некоторое время назад здесь - person MikeSW; 22.09.2016
comment
Хорошая статья, смотрите мой комментарий к ней. - person Constantin Galbenu; 23.09.2016