События цепочки источников событий

Я реализую ограниченный контекст, используя источник событий, но столкнулся с проблемой. Скажем, я моделирую игру в футбол, и меня интересуют как отдельные забитые голы (кто их забил и т. д.), так и общий счет. Поэтому, если у меня есть корень агрегата Match, я в идеале хочу, чтобы события вызывались с именами GoalScored и ScoreChanged. Причина, по которой я хочу, чтобы оценка явно указывалась из домена, заключается в том, что я не хочу, чтобы много разных слушателей и, возможно, других ограниченных контекстов вычисляли одно и то же.

Это кажется простым, но: объект Match имеет метод Goal(), который добавляет новую цель. В духе источника событий это не изменяет состояние Match напрямую, а вызывает событие GoalScored, которое обрабатывается в Match, которое затем изменяет состояние (а также событие, передаваемое денормализаторам). Таким образом, с точки зрения повышения ScoreChanged, счет фактически не изменился, пока не было обработано событие GoalScored, поэтому я должен вызвать другое событие в ответ на это событие (ScoreChanged), эффективно связывая события? Я так не думаю, для начала, когда совокупный корень перезагружается из хранилища событий, каждый раз будет создаваться множество дополнительных событий в ответ на каждый GoalScored.

Я также подумал о том, чтобы выяснить, какой счет будет в обработчике команд, который повышает GoalScored, что-то вроде ситуации «что, если». Затем я мог вызвать оба события в обработчике команд. Хотя я бы предпочел этого не делать - это просто не кажется "правильным". Вычислить счет в футболе достаточно просто, но в других играх (например, в крикете) требуется больше усилий.

Я мог бы поместить и гол, и счет в событие GoalScored, что достаточно справедливо, но опять же это не кажется правильным - счет не имеет ничего общего с событием GoalScored как таковым.

Во всех примерах, используемых при обсуждении источников событий, похоже, используется домен электронной коммерции «Клиент/Заказ», и я никогда не видел подобного случая.

У кого-нибудь есть опыт решения подобных ситуаций?

Спасибо


person user303754    schedule 15.01.2013    source источник


Ответы (3)


Выбор чистых событий предметной области, как и любое другое моделирование, должен привести к концепциям, которые отражаются в предметной области. Вы говорите, что «счет не имеет ничего общего с событием GoalScored как таковым». Но это так. В футболе единственный способ изменить счет — это забить гол. Тем не менее, цели можно вернуть, например. через вызовы вне игры или другие штрафы. Непонятно, хотите ли вы моделировать это или нет.

Обычно доменный метод генерирует несколько событий одновременно. Хорошая структура позволит легко рассматривать их как связку, например. как единый коммит. Почему бы не генерировать одновременно событие GoalScored и ScoreChanged?

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

person Sebastian Good    schedule 15.01.2013
comment
Да, я, вероятно, просто буду генерировать оба события из одного метода. В домене есть команды — по крайней мере, если мы говорим об одном и том же типе команд. StartMatch, PlayerSentOff и т. д. и т. д. Что касается последнего пункта, то это в значительной степени похоже на систему, которая преобразует потоки событий в большее количество событий, безусловно, для подсчета очков. Спасибо за ответ. - person user303754; 17.01.2013

Одна вещь, которая часто помогает, когда вы думаете об источнике событий, — это обратите внимание на время — вы говорите StartMatch, но в смысле события это на самом деле событие MatchStarted.

Что касается ScoreChanged, вы используете это событие вне матча? Если нет, Score должен быть единственной общедоступной частью, а событие GoalScored просто изменяет это. Это незначительно удерживает CQRS (то, как я получаю оценку, не зависит от того, как я ее изменяю). Затем Score может внутренне хранить состояние или может воспроизводить все события GoalScored, чтобы получить число каждый раз, когда он вызывается. «Ощущение» правильно спроектированных решений на основе событий всегда может восстановить любое состояние из событий.

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

person Mathieson    schedule 13.06.2014

У меня есть этот проект с открытым исходным кодом для поиска событий в scala, который содержит примеры того, как корзина работает с его использованием. На всякий случай полезно для вас https://github.com/politrons/Scalaydrated

person paul    schedule 30.10.2016