Недавно я начал свою первую попытку разработать веб-приложение для продажи билетов, используя принципы проектирования, ориентированные на предметную область, в сочетании с поиском событий и CQRS.
Поскольку это моя первая попытка отойти от традиционного подхода CRUD и перейти в мир DDD, я уверен, что у меня много вещей, спроектированных неправильно, поскольку DDD требует больших усилий, чтобы придумать правильное разделение доменов, ограниченных контекстов и т. Д.
В моем дизайне у меня есть обработчики команд, которые принимают команду, инициируют задание (единицу работы), загружают необходимые агрегаты из репозитория агрегатов (который загружает агрегаты из хранилища событий путем воспроизведения событий) и манипулируют агрегатами. через открытые действия каждого агрегата, а затем закройте задание.
Агрегаты предоставляют действия, которые фактически вызывают события. Например, company.Create(firmName, address, taxid, ...)
выдает CompanyCreated
событие и применяет его к себе. Когда задание почти завершено, все события из всех агрегатов, загруженных в контексте этого задания, собираются и сохраняются в хранилище событий.
Теперь я попал в ситуацию, которая, я уверен, очень распространена, когда у меня есть отношения между агрегатами. Например, Customer
имеет Contacts
, или SupportAgent
является членом Department
. Это агрегаты в моем дизайне.
Возьмем пример Department
. Состояние Department
состоит из заголовка, описания, некоторых других свойств и списка SupportAgent
идентификаторов тех агентов, которые являются членами этого отдела. Состояние SupportAgent
состоит из имени, фамилии, номера телефона, электронной почты, ... и списка Department
идентификаторов тех отделов, членом которых является этот агент.
Теперь при обработке команды типа AddAgentToDepartment(agentId, departmentId)
выдаются два события. DepartmentAdded
выдается соответствующему агенту, который добавит идентификатор отдела в состояние агента, и SupportAgentAdded
выдается соответствующему отделу, который добавит идентификатор агента в состояние отдела.
Мой первый вопрос: Правильно ли сохранять идентификаторы связанных агрегатов в состоянии агрегата? Под словом «правильно» я подразумеваю, является ли это наилучшей практикой? Или есть другой способ (например, поддержание отношений в виде сущности / агрегата «DepartmentMemberManager» или что-то в этом роде. На самом деле эта сущность или что-то еще здесь является чем-то вроде синглтона. Есть ли такая вещь в мире DDD)?
Другая моя мысль связана с воспроизведением событий. В предыдущем примере генерируются два события, но для обновления представлений необходимо обработать только одно из них, поскольку оба события описывают один и тот же переход в состоянии системы (агент и отдел связаны). Я решаю обрабатывать только событие SupportAgentAdded
для обновления представлений. Мой обработчик событий выполняет сценарий SQL для обновления соответствующих таблиц базы данных, чтобы отразить текущее состояние системы.
Что происходит, если нам нужно воспроизвести некоторые события, чтобы привести в согласованное состояние только определенный агрегатный вид? В частности, когда я хочу воспроизвести события для агента поддержки, будут воспроизводиться только DepartmentAdded
событий, и эти события никем не обрабатываются, поэтому представления не будут обновляться. Правильно ли частично воспроизводить некоторые события или все события в хранилище событий должны воспроизводиться, чтобы привести всю систему в согласованное состояние?
Если вы являетесь экспертом по DDD и ES или, по крайней мере, у вас есть опыт, я хотел бы получить несколько подсказок о том, что, по вашему мнению, я делаю или думаю неправильно и в каком направлении мне следует смотреть.