Как бороться с обновлением Entity (CRUD) и Domain Events с использованием DDD?
Я знаю, что DDD хорошо работает с пользовательским интерфейсом на основе задач, но я реорганизую устаревшее приложение, в котором у меня Anemic Domain Model (многие сеттеры без бизнес-логики).
Одним из первых шагов было сделать так, чтобы он достиг модели и добавил Доменные События. При добавлении событий для создания (TaskCreated
в конструкторе) и удаление (TaskRemoved
) модель - простой процесс, я борюсь с обновлением модели.
У нас есть RESTful API с PUT /tasks/{id}
конечная точка. Под капотом фреймворк отображает тело ответа на объект DTO и затем вызывает сеттеров один за другим:
task.setText('new text');
task.setStartDate(newStartDate);
// and so on
Я хочу прослушать какое-то событие при обновлении задачи и обновить его, например, в Календаре Google. Как вы можете визуализировать, если я записываю события в каждом setter
(TextChanged, StartDateChanged) и послушайте их всех, в результате я получу множество вызовов API для API Google, а это не то, что мне нужно.
Вопрос: как мне правильно работать с операцией обновления? Должен ли я заменить все эти setters
звонки с одним update(newData)
позвонить и отправить только одно доменное событие? Как сделать только один вызов API для календаря Google после обновления задачи?
2 ответа
как правильно работать с операцией обновления?
Обычный ответ заключается в том, что события домена не являются частью объекта, который вы модифицируете, а описывают изменения в отдельной структуре данных.
С анемичной моделью, я бы ожидал, что вызывающая сторона будет нести ответственность за события. Вероятно, это не та структура, если она просто отображает поля DTO в задаче. Вы хотите, чтобы события определялись в той точке кода, которая понимает бизнес-контекст изменений. Другими словами, вы, вероятно, хотите TaskRescheduled
скорее, чем TaskUpdated
,
В первом черновике вы можете просто опубликовать событие в тот момент, когда вы знаете, что сохранение прошло успешно.
Более надежным является сохранение списка событий с заданием. Это дает вам лучшие истории о надежном обмене сообщениями - см. Udi Dahan Reliable Messaging без распределенных транзакций, чтобы лучше понять, где это происходит.
Если модель предметной области не является анемичной, вы действительно определите событие в обновлении Задачи (событие в модели данных будет по-прежнему отделено от состояния задачи).
Я предпочитаю способ "одно событие для набора", потому что действие обновления иногда является лишь вариантом использования, представьте себе, что вам придется позже, в домене, изменить только одно поле объекта из-за внешнего процесса, вы должны будете есть команда, представляющая этот вариант использования, а не полное обновление.
Теперь возникает вопрос: как отследить события, которые были запущены на основе одного варианта использования? Проще говоря, используйте какой-то идентификатор корреляции, например, идентификатор запроса.
Для этого вы можете использовать список, содержащий события домена, и при сохранении транзакции вы отправляете события и, поскольку они были созданы в одном и том же логическом контексте, они будут иметь одинаковый идентификатор корреляции.