Каковы наилучшие методы внедрения нового BC в приложение DDD?

Это теоретический вопрос о введении новых БК в системе используем ES и CQRS с DDD. Так что конкретных примеров не будет.

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

Например, у нас есть старая БК A, и мы вводим новую БК B. Оба публикуют события предметной области, которые мы называем a и b. В новой системе важен порядок, например, b1 всегда должно стоять после a1, но перед a2. Что мы можем сделать, когда у нас уже есть последовательность a1, a2, a3 в хранилище событий? Должны ли мы вводить b1 после a1 и так далее? Является ли это жизнеспособным решением для огромного хранилища событий? Безусловно, потребуется много времени, чтобы последовательно переиграть все старые события и отреагировать на них. Как мы можем предотвратить отправку электронного письма клиенту, обработав недавно созданное событие b1, которое реагирует на тему пятилетней давности? Есть ли шаблон для предотвращения подобных проблем?


person inf3rno    schedule 24.11.2015    source источник
comment
Вы развертываете свои компоненты (ограниченные контексты) как отдельные приложения, как и должны? Они звучат не так «ограниченно», как должны.   -  person abuzittin gillifirca    schedule 25.11.2015
comment
@abuzittingillifirca Как я уже писал, это теоретический вопрос. В настоящее время я изучаю DDD по книгам. Я не начну ни один проект, пока полностью не пойму его.   -  person inf3rno    schedule 25.11.2015
comment
@abuzittingillifirca Я думаю, что мое неправильное понимание BC-s и источников событий глубже, чем я. Ваш вопрос в этом комментарии действительно хорош. Задам еще вопрос в теме.   -  person inf3rno    schedule 09.01.2016


Ответы (2)


Анализ проблемы

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

Если вы введете новый BC B в существующую систему, это означает, что система работала без B. Это ясно из приведенного выше утверждения и имеет следующие последствия:

  • События, которые B создал бы в ответ на события A, публиковать не нужно. Ни одна другая система не должна предпринимать никаких действий на основе этих событий, поскольку они являются искусственными.
  • Вы можете выйти в эфир с B в любое время. Единственное, что вам нужно сделать заранее, это синхронизировать B с текущим состоянием системы.

Получение B в синхронизации

Это несложно, если вы спроектируете B соответствующим образом.

  1. Во-первых, вам нужен механизм режима воспроизведения для импорта всех событий домена в B без публикации событий из B в ответ. Если вы используете событие, вам, конечно, нужно хранить события Bs внутри. источники, но не публикуйте их. Также убедитесь, что B не изменяет состояние мира в режиме повтора другими способами, например. не отправлять электронные письма.
  2. Затем переключите B в живой режим. Теперь B потребляет новые события из системы, а также публикует свои собственные.

Упомянутая вами проблема с упорядочением событий возникает только тогда, когда вы используете единое хранилище событий для всех событий предметной области, а также используете это хранилище для публикации событий. Если это так, вам нужно пометить события Bs как «внутренние» на этапе воспроизведения и скрыть их от механизма публикации.

Примечание. Если B является чисто реактивным BC (это может иметь место для очень простого BC), то вам даже не нужны повторы. Но большинство БК, вероятно, так и делают.

person theDmi    schedule 25.11.2015
comment
Имеет смысл. :-) Подожду несколько дней, прежде чем принять, может и другие ответят. Кстати. Как вы думаете, допустимо ли в некоторых случаях переписывать историю, например, если вы добавляете новое свойство в существующий класс событий? - person inf3rno; 25.11.2015
comment
Да, это ES-вариант миграции. Я стараюсь избегать этого, но иногда это просто самое чистое решение. Однако протестировать миграцию в QA env — хорошая идея :-) - person theDmi; 25.11.2015
comment
@inf3rno если вы добавите новое свойство к существующему событию, это должно быть некритическое изменение, чтобы не было необходимости в переносе. - person abuzittin gillifirca; 25.11.2015
comment
@abuzittingillifirca Что, если новый код требует этого свойства? Должны ли мы вместо этого версионировать классы событий? - person inf3rno; 25.11.2015
comment
@inf3rno Можешь. Но если вы можете заполнить свойство постфактум, то вы ищете это значение откуда-то, возможно, вам следует продублировать источник, в котором вы его ищете. - person abuzittin gillifirca; 25.11.2015
comment
FWIW, я бы никогда не изменил историю, кроме как в абсолютном крайнем случае. - person Phil Sandler; 25.11.2015

Прежде всего, DDD не требует источника событий.

у нас есть старый BC A, и мы вводим новый BC B. Оба публикуют события предметной области, которые мы называем a и b. В новой системе важен порядок, например, b1 всегда должен следовать после a1, но перед a2.

События могут быть не по порядку, даже в одном и том же компоненте (в ограниченном контексте). Целостность транзакций гарантируется только внутри агрегатов.

когда у нас уже есть последовательность a1, a2, a3 в хранилище событий?

Не имеет значения. Кстати, у вас нет этой гарантии с базами данных SQL, если вы не работаете в изоляции SERIALIZABLE. (или его аналог у поставщика). Подсказка: производительность настолько высока, что она никогда не включается по умолчанию; поэтому вы его не используете.

Обратите особое внимание на эту часть в приведенной выше ссылке:

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

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

Должны ли мы вводить b1 после a1 и так далее?

Поскольку ваши компоненты должны иметь возможность обрабатывать не по порядку (и дублировать события), нет

Что мы можем сделать,

В зависимости от технологии, используемой для интеграции компонентов, и семантики сообщений:

  • Если вы читаете события из веб-сервиса, фида, таблицы БД; чтобы он никогда не исчезал; вы можете игнорировать событие, пока оно не станет актуальным.

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

  • Вы можете использовать шаблон, известный как Saga/Process Manager.

  • Есть ли вообще условия гонки?

person abuzittin gillifirca    schedule 25.11.2015