Я не могу придумать концепцию смешения DDD с ES. Я считаю события частью домена. Учитывая, что нет проблем с публикацией их из репозитория во внешний мир и сохранением моделей в чистоте и простоте. Но кроме этого должна быть возможность переиграть их обратно на конкретный агрегат. Здесь моя проблема возникает. Я хотел бы сохранить свои доменные модели чистыми и простыми объектами, которые остаются независимыми от lib / framework.
Чтобы применить прошлые события к агрегату, агрегат должен знать, что он является частью структуры ES (поэтому он не должен оставаться чистым доменным объектом). Поскольку основная работа агрегата заключается в том, чтобы включить некоторые бизнес-инварианты, которые могут эволюционировать с течением времени, невозможно применять старые события с использованием агрегатного API. Например, существует совокупный пост с дочерними сущностями Комментарии. Сегодняшняя публикация позволяет добавлять 10 комментариев, а метод addCommnet () защищает это правило. Но это не всегда так. Год назад пользователю было разрешено добавить до 20 комментариев. Таким образом, применение прошлых событий может не соответствовать текущим правилам.
Бродвей (популярная библиотека PHP CQRS) решает эту проблему, применяя события без предварительной проверки. Метод addCommnet () просто проверяет его на соответствие нашим инвариантам, а затем обрабатывает события приложения. Событие Applyinig само по себе не выполняет дальнейшую проверку. Это здорово, но я воспринимаю это как высокий уровень интеграции в моих предметных моделях. Действительно ли моей доменной модели нужно знать что-либо об инфаструктуре (которая является стилем ES для сохранения данных)?
РЕДАКТИРОВАТЬ:
Чтобы сформулировать проблему простейшими словами: есть ли возможность избавиться от всех этих методов applyXXX () из агрегата?
EDIT2:
Я написал (немного хакерский) PoC этой идеи с PHP — GitHub
Отказ от ответственности: я CQRS Framework парень.
Бродвей (популярная библиотека PHP CQRS) решает эту проблему, применяя события без предварительной проверки.
Так работает каждый CQRS Aggregate, события не проверяются, потому что они отражают факты, которые уже произошли в прошлом. Это означает, что применение event
не бросает exceptions
, Когда-либо.
Чтобы применить прошлые события к агрегату, агрегат должен знать, что он является частью структуры ES (поэтому он не должен оставаться чистым доменным объектом).
Нет, это не так. Он должен знать о своих прошлых событиях. Это хорошо.
Сегодняшняя публикация позволяет добавлять 10 комментариев, а метод addCommnet () защищает это правило. Но это не всегда так. Год назад пользователю было разрешено добавить до 20 комментариев. Таким образом, применение прошлых событий может не соответствовать текущим правилам.
Что держит тебя aggregate
от игнорирование это событие или интерпретировать иначе, чем 1 год назад ?!
Этот конкретный случай должен заставить вас задуматься о мощи CQRS: записи имеют другую логику, чем чтения. Вы применяете события к агрегату, чтобы проверить будущие команды, которые приходят к нему (сторона записи / команды). Отображение этих 20 событий обрабатывается другой логикой (сторона чтения / запроса).
Здесь моя проблема возникает. Я хотел бы сохранить свои доменные модели чистыми и простыми объектами, которые остаются независимыми от lib / framework.
CQRS позволяет поддерживать ваши агрегаты в чистоте (без побочных эффектов), без зависимости от какой-либо библиотеки и просто. Я делаю это, используя стиль, представленный cqrs.nu, уступая событиям. Это означает, что агрегированные методы обработчиков команд на самом деле генераторы.
Прочитанные модели также могут быть очень простыми, обычными неизменяемыми объектами PHP. Только средство чтения модели чтения имеет зависимость от постоянства, но это можно инвертировать с помощью interface
,
Я не могу придумать концепцию смешения DDD с CQRS.
Судя по всему, вы не можете полностью разобраться в миксе DDD и источник событий. CQRS и Event Sourcing — это отдельные идеи (которые хорошо сочетаются).
Сегодняшняя публикация позволяет добавлять 10 комментариев, а метод addCommnet () защищает это правило. Но это не всегда так. Год назад пользователю было разрешено добавить до 20 комментариев. Таким образом, применение прошлых событий может не соответствовать текущим правилам.
Это абсолютно верно. Обратите внимание, однако, что это также верно, что если у вас было не пост, содержащий 15 комментариев, и вы пытаетесь составить «правило», поскольку разрешено только 10 комментариев, но проблема остается.
Мой ответ на эту загадку (в обоих стилях) заключается в том, что вам нужно немного отличаться от понимания ответственных обязанностей.
Ответственность доменной модели поведение; он описывает, какие состояния достижимы из текущего состояния. Модель предметной области не должна ограничивать вас в плохое состояние, оно должно препятствовать хорошим состояниям становление плохие состояния.
В первой версии можно сказать, что состояние Post
включает в себя TwentyList of Comments
где TwentyList — это (неожиданно) контейнер, который может содержать до 20 идентификаторов комментариев.
Во второй версии, где мы хотим сохранить ограничение в 10 комментариев, мы не меняем TwentyList
к TenList
, потому что это дает нам головную боль обратной совместимости. Вместо этого мы изменили правило домена, сказав, что «к сообщению с 10 или более комментариями нельзя добавлять комментарии». Данные схема неизменен, и нежелательные состояния все еще представимы, но разрешенное состояние переходы сильно ограничены.
По иронии судьбы, хорошая книга, которую можно почитать, чтобы узнать больше, — это Грег Янг. Управление версиями в системе источников событий. На высоком уровне урок заключается в том, что управление версиями событий — это просто управление версиями сообщений, а состояние — это просто сообщение, оставленное предыдущей моделью для текущей модели.
Типы значений не об ограничениях правил, они о семантический ограничения.
Имейте в виду, что сроки очень разные; поведение о сейчас а также следующий, но государства о прошлое. Предполагается, что состояния должны длиться гораздо дольше, чем поведение (с соответствующими инвестициями в проектный капитал).
Действительно ли моей модели предметной области нужно что-то знать об инфраструктуре (в стиле ES для сохранения данных)?
Нет, модель предметной области не должна знать об инфраструктуре.
Но события не инфраструктура — они государство. Журнал AddComment
а также RemoveComment
события это состояние, как список Comment
Записи гос.
Наиболее общая форма «поведения» — это функция, которая принимает текущее состояние в качестве входных данных и генерирует события в качестве выходных данных.
List<Event> act(State currentState);
как мы всегда можем на внешнем уровне, взять события (которые представляют собой неразрушающее представление состояния и построить из них состояние).
State act(State currentState) {
List<Event> changes = act(currentState)
State nextState = currentState.apply(changes)
return nextState
}
List<Event> act(List<Event> history) {
State initialState = new State();
State currentState = initialState.apply(changes)
return act(currentState)
}
State act(List<Event> history) {
// Writing this out long hand to drive home the point
// we could of course call act: List<Event> -> State
// to avoid duplication.
List<Event> changes = act(history)
State initialState = new State()
State currentState = initialState.apply(history)
State nextState = currentState.apply(changes)
return nextState;
}
Дело в том, что вы можете реализовать поведение в самом общем случае, добавить несколько адаптеров, а затем позволить сантехнику выбрать, какая реализация является наиболее подходящей.
Опять же, разделение обязанностей — это ваша путеводная звезда: заявите, что управляет тем, что есть, поведение, которое управляет разрешенными изменениями, и сантехника / инфраструктура — все это отдельная проблема.
Проще говоря: я ищу возможность избавиться от многих методов applyXXX () (или похожих в языках с методами перегрузки) из моего агрегата
applyXXX
это просто функция, которая принимает State
и Event
в качестве аргументов и возвращает новый State
, Вы можете использовать любое правописание и область видимости, которую вы хотите для этого.
Мой ответ очень короткий. На самом деле, вы боретесь с источником событий, а не с CQRS.
Если обработка какого-либо события со временем меняется, у вас действительно есть два сценария:
Эти сценарии не имеют отношения к языкам программирования и средам. Event-Sourcing в целом гораздо больше о бизнесе, чем о любой технологии.
Я бы поддержал книгу рекомендации Грега.
Я думаю, что ваша проблема в том, что вы хотите проверять события, когда они применяются, но применение и проверка — это два разных этапа совокупного действия. Когда вы добавляете комментарий методом addComment (событие), вы должны проверить логику, и этот метод генерирует событие, когда вы отвечаете на событие, эта логика больше не проверяется. Прошлое событие не может быть изменено, и если ваш агрегат выдает исключение с событием ответа, что-то не так с вашим агрегатом. Вот как я понимаю твою проблему.