Система репутации в стиле SO с CQRS и Event Sourcing - PullRequest
3 голосов
/ 10 сентября 2011

Я погружаюсь в свои первые набеги с CQRS и Event Sourcing, и у меня есть несколько моментов, по которым я хотел бы получить некоторые рекомендации.Я хотел бы внедрить систему репутации в стиле SO.Кажется, это идеально подходит для этой архитектуры.

В качестве примера приведем SO.Скажем, за вопрос проголосовали, это генерирует UpvoteCommand, который увеличивает общий балл вопросов и запускает QuestionUpvotedEvent.

Похоже, что совокупность пользователей автора должна подписаться на QuestionUpvotedEvent, что может повысить репутациюГол.Но как / когда вы делаете эту подписку мне не понятно?В примере Грега Янгса обработка события / команды подключена в global.asax, но, похоже, это не связано с какой-либо маршрутизацией на основе идентификатора агрегата.

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

Что я здесь не так делаю?

Любое руководство высоко ценится.

РЕДАКТИРОВАТЬ

Я предполагаю, что мы говорим здесь о межагрегатном взаимодействии между вопросами и пользовательскими агрегатами.Одно решение, которое я вижу, состоит в том, что на QuestionUpvotedEvent подписывается ReputationEventHandler, который может затем извлечь соответствующий пользовательский AR и вызвать соответствующий метод для этого объекта, например YourQuestionWasUpvoted.Это, в свою очередь, сгенерировало бы специфичное для пользователя событие UserQuestionUpvoted, тем самым сохраняя возможность воспроизведения в будущем.Это направление в правильном направлении?

РЕДАКТИРОВАТЬ 2

См. Также обсуждение групп Google здесь .

Ответы [ 4 ]

6 голосов
/ 13 сентября 2011

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

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

Что бы я сделал в этой ситуации:

  • VoteUpQuestionCommand вызывается.
  • Обработчик для VoteUpQuestionCommand вызовов:

    IQuestionVotingService.VoteUpQuestion (Guid questionId, Guid UserId);

  • Затем он объединяет вопрос и совокупности пользователей, вызывая соответствующие методы для обоих, такие как user.IncrementReputation (int amount) и question.VoteUp (). Это поднимет два события; UsersReputationIncreasedEvent и QuestionUpVotedEvent соответственно, которые будут обрабатываться стороной запроса.

2 голосов
/ 12 сентября 2011

Мое эмпирическое правило: если вы общаетесь между AR, используйте сагу.Он держит вещи в пределах транзакции и делает ваши ссылки явными => проще в обработке / обслуживании.

0 голосов
/ 21 октября 2016

Это старый вопрос, помеченный как ответ, но я думаю, что можно что-то добавить к нему. После нескольких месяцев чтения, практики и создания небольшой платформы и прикладной базы на CQRS + ES, я думаю, CQRS пытается отделить зависимости компонентов и их обязанности. В некоторых ресурсах пишите для каждой команды, которую вы должны изменить максимум на один агрегат в обработчике команд (вы можете загрузить более одного агрегата в обработчик, но может изменить только один из них). Так что в вашем случае я думаю, что лучшая практика - @Tom answer, и вы должны использовать сагу. Если ваш фреймворк не поддерживает saga (Как и мой маленький фреймворк), вы можете создать какой-нибудь обработчик событий, например UpdateUserReputationByQuestionVotedEvent. В этом обработчик создает UpdateUserReputation(Guid user id, int amount) ИЛИ UpdateUserReputation(Guid user id, Guid QuestionId, int amount) ИЛИ UpdateUserReputation(Guid user id, string description, int amount). После того, как команда отправляется в обработчик, обработчик загружает пользователя по идентификатору пользователя и обновляет состояния и свойства. В этом типе обработки вы можете создать более сложный сценарий или рабочий процесс.

0 голосов
/ 10 сентября 2011

У агрегата пользователя должно быть событие QuestionAuthored ... в этом случае он подписывается на QuestionUpvotedEvent ... аналогично он должен иметь QuestionDeletedEvent и / или QuestionClosedEvent, в котором он выполняет надлежащую обработкукак отписаться от QuestionUpvotedEvent и т. д.

РЕДАКТИРОВАТЬ - согласно комментарию:

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

...