DDD, Магазин событий, UI

У меня есть проект, который разработан или, по крайней мере, должен соответствовать хорошо известным принципам DDD.

  1. Back - DDD + CQRS + Магазин событий

  2. UI - ngrx/store

У меня много вопросов по этому поводу, но сейчас я буду придерживаться этих двух:

  1. Как следует обновить хранилище пользовательского интерфейса после выполнения одной команды / действия?

а) подписаться на response.ok

б) прослушивать доменные события

в) вызвать общее событие, содержащее созданный / обновленный / удаленный объект?

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

3 ответа

Решение

Как следует обновить хранилище пользовательского интерфейса после выполнения одной команды / действия?

Командные методы из моих Агрегатов возвращают void (с учетом CQS); таким образом, конечные точки REST, которые получают запросы команд, отвечают только чем-то вроде OK, command is accepted, Затем это зависит от того, как команда обрабатывается внутри внутреннего сервера:

  • если команда обрабатывается синхронно, то простое OK, command is accepted достаточно, поскольку пользовательский интерфейс обновится сам, и новые данные будут там;
  • если команда обрабатывается асинхронно, то все усложняется, и должен быть возвращен какой-то идентификатор команды, поэтому ответ OK, command is accepted and it has the ID 1234-abcd-5678-efgh; please check later at this URI for command completion status

В то же время вы можете прослушивать события домена. Я делаю это, используя отправленные сервером события, которые отправляются из серверной части в пользовательский интерфейс; это полезно, если пользовательский интерфейс имеет веб-интерфейс, поскольку может быть открыто более одного окна браузера, и данные будут обновляться в фоновом режиме для страниц; это хорошо, клиент доволен.

О включении некоторых данных со стороны чтения в ответ команды: это зависит от вашего конкретного случая; Я избегаю этого, потому что это подразумевает чтение при записи, и это означает, что я не могу отделить запись от чтения на более высоком уровне; Мне нравится иметь возможность независимо масштабировать запись из прочитанной части. Итак, response.ok это самое чистое решение. Кроме того, это подразумевает, что конечная точка команды / записи делает некоторые предположения относительно запроса вызывающей стороны; зачем обработчику команды / конечной точке команды предполагать, какие данные нужны вызывающей стороне? Но могут быть исключения, например, если вы хотите уменьшить количество запросов или если вы используете шлюз API, который также выполняет READ после отправки команды на внутренний сервер.

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

Я никогда не отправляю весь Aggregate при использовании CQRS; у вас есть модели чтения, поэтому каждый агрегат имеет различное представление для каждой модели чтения. Таким образом, вы должны создать модель чтения для каждого компонента пользовательского интерфейса, таким образом вы сохраняете и отправляете только те данные, которые отображаются в пользовательском интерфейсе, а не какой-то богоподобный объект, содержащий все, что кому-либо нужно было бы отображать в любом месте.

Команды в основном попадают в одну из двух категорий: команды создания и остальные.

Создание команд

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

  • Я считаю, что команды создания в CQS и CQRS могут возвращать какой-либо идентификатор или местоположение: см. Мой ответ здесь. Этот идентификатор, вероятно, будет известен обработчику команды, который может вернуть его в своем ответе. Это соответствует хорошо 201 Created + Location Заголовок в REST.

  • Вы также можете попросить клиента сгенерировать идентификатор. В этом случае см. Ниже.

Все остальные команды

Клиент, очевидно, имеет адрес объекта. Он может просто запросить свое местоположение после получения подтверждения от HTTP-части. При желании вы можете опрашивать местоположение, пока что-то не покажет, что команда была успешной. Это может быть идентификатор версии ресурса, статус, на который указал Константин, канал Atom и т. Д.

Также обратите внимание, что это может быть проще для Command Handler, чтобы вернуть статус успеха операции, это спорно ли, что на самом деле нарушает ОКК или нет (опять же, см ответ выше).

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

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

Другие вопросы по тегам