Чтение модели с данными из нескольких агрегатных корней (в разных контекстах) - PullRequest
0 голосов
/ 24 мая 2019

Мне любопытно, как объединить данные из нескольких агрегатных корней в модели чтения для агрегатного корня из источника. Можно попытаться взять простой пример:

Если у меня есть объединенный корень с именем Cart, который поддерживает следующие события в своем потоке событий (свойства в скобках - имейте в виду, это простой пример):

AddProductToCart(cartId: Int, productId: Int)
RemoveProductFromCart(cartId: Int, productId: Int)
AddUserLicenseToProduct(cartId: Int, productId: Int, userId: Int)
RemoveUserLicenseFromProduct(cartId: Int, productId: Int, userId: Int)
EmptyCart(cartId: Int)

Это нормально при проецировании прочитанных моделей с данными, поступающими из этого потока событий. Я могу, например, проецировать объект корзины, который выглядит примерно так:

Cart(cartId: Int, products: List[Product])

Product(productId: Int, userLicenses: List[UserLicense])
UserLicense(userId: Int)

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

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

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

Я полагаю, что другим решением было бы дублировать данные из других совокупных корней в хранилище других приложений / служб / контекстов. Например, скопируйте данные productName и productType в хранилище, которое принадлежит приложению Cart, но не должно быть частью потока событий Cart. В этом случае приложение Cart должно будет прослушивать события (например, ProductCreated, ProductNameChanged), чтобы обновлять данные. Я думаю, это может быть жизнеспособным решением.

Ответы [ 2 ]

1 голос
/ 28 мая 2019

Каждый ограниченный контекст должен быть слабо связанным. У нас была похожая проблема с двумя нашими контекстами. Мы нашли решение использовать рабочие процессы, создавая все связи между контекстами в этих файлах. В котором мы могли бы синхронизировать необходимые схемы, подписавшись на обработчик событий. Поскольку мы использовали Elixir, мы использовали библиотеку Comaged, которая имеет свою собственную шину событий.

Но в распределенных системах вы можете использовать Apache Kafka. В конце концов, я думаю, что более простое решение должно сделать ваши схемы максимально чистыми (оно также поможет вам соблюдать соответствие GDPR) и управлять всей вашей коммуникацией через отдельный уровень с помощью обработчика событий.

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

https://leanpub.com/buildingconduit/read

0 голосов
/ 27 мая 2019

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

Другим вариантом будет то, что событие будет содержать как можно меньше данных из связанного ограниченного контекста. Как минимум, это будет идентификатор. Однако в большинстве случаев некоторые данные должны быть денормализованы, чтобы иметь смысл. Например, было бы полезно, если бы описание продукта было денормализовано в Cart и в конечном итоге Order, особенно когда кто-то меняет описание после того, как я сделал свой выбор. Описание может измениться с Blue pen на Red pen, что резко изменит то, что я намеревался приобрести. В этом случае Product в вашем Shopping BC может быть представлен объектом значения, который содержит Id вместе с Description.

Если вы теперь хотите дополнить данные только для чтения, у нас остается только возможность извлечь их из источника BC. Это может быть сделано в модели чтения с использованием некоторого API (Rest / ACL) и затем сохраненных данных. Чтобы сделать его более отказоустойчивым, можно выбрать инфраструктуру обмена сообщениями / служебной шины для обработки извлечения дополнительных данных и обновления соответствующей записи модели чтения.

...