Domain events и websocket

Обсуждаем, как правильно строить приложения
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Domain events и websocket

Сообщение sda »

Изучаю вопрос, как уведомлять UI клиента о том, что данные, которые ему интересны изменились. Например UI должен обновить список пользователей онлайн в чате, если кто-то вошел на сайт, покинул сайт или сменил комнату чата на другую. Для каждого из этих действий (вошел/покинул/сменил) у сущности User есть свой метод. Я могу внутри этих методов выбрасывать доменные события.

Но теперь хочется понять, как довести доменные события до UI клиента. Протокол передачи данных - websocket. Я думал о методе сервиса ChatService::getUsers, который возвращает клиенту список пользователей онлайн в чате и подписывает клиента на доменные события (вошел/покинул/сменил). То есть это некий аналог GET запроса в HTTP протоколе, но отличие в том, что он не просто отдает данные и забывает про клиента, он обязуется в будущем уведомлять клиента о всех изменениях связанных с этим запросом (вошел/покинул/сменил).

Но меня настораживает то, что количество доменных событий будет расти и соответственно количество доменных событий, на которые необходимо подписываться и обрабатывать их в ChatService::getUsers тоже будет увеличиваться. То есть когда в системе будет появляться новое доменное событие, то разработчику нужно как-то знать, каким методам, каких сервисов это доменное событие может быть интересно и соответственно внести правки в методы этих сервисов, чтобы каждый из них, каким-то своим образом обрабатывал это новое событие.

Например доменное событие "вошел на сайт" и "покинул сайт" может влиять не только на отображение пользователей в чате, но и также на страницу с информацией о пользователе. Соответственно обработку этих доменных событий нужно будет сделать не только в ChatService::getUsers, который отдает данные для формирования списка пользователей в чате, но и в UserService::getById, который отдает данные для формирования страницы с информацией о конкретном пользователе. И например, если забыть сделать обработку этих доменных событий в UserService::getById, то ничего страшного не произойдет, страница с информацией о пользователе просто никак не будет реагировать на события входа и выхода на сайт.

Не приведет ли это к аду, когда новое доменное событие требуется проанализировать, каким UI экранам оно может быть интересно и соответственно внести обработку этого нового доменного события в различные методы различных сервисов? Может быть есть какие-то другие решения уведмолять UI об изменившихся данных?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Domain events и websocket

Сообщение zelenin »

sda писал(а):Но теперь хочется понять, как довести доменные события до UI клиента. Протокол передачи данных - websocket. Я думал о методе сервиса ChatService::getUsers, который возвращает клиенту список пользователей онлайн в чате и подписывает клиента на доменные события (вошел/покинул/сменил). То есть это некий аналог GET запроса в HTTP протоколе, но отличие в том, что он не просто отдает данные и забывает про клиента, он обязуется в будущем уведомлять клиента о всех изменениях связанных с этим запросом (вошел/покинул/сменил).
итак, в сущности у вас генерятся доменные события, в репозитории при сохранении сущности вы вытаскиваете нагенеренные за сессию события и кидаете их в шину (или что там у вас события разруливает). В шине стандартная ситуация с событиями: сервер вебсокета подписывается на события и при их возникновении пишет что-то в чат. Это если у вас шина асинхронная. Иначе записываем события в таблицу, вебсокет-сервер оттуда их читает.
sda писал(а):Но меня настораживает то, что количество доменных событий будет расти и соответственно количество доменных событий, на которые необходимо подписываться и обрабатывать их в ChatService::getUsers тоже будет увеличиваться.

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

Например доменное событие "вошел на сайт" и "покинул сайт" может влиять не только на отображение пользователей в чате, но и также на страницу с информацией о пользователе. Соответственно обработку этих доменных событий нужно будет сделать не только в ChatService::getUsers, который отдает данные для формирования списка пользователей в чате, но и в UserService::getById, который отдает данные для формирования страницы с информацией о конкретном пользователе. И например, если забыть сделать обработку этих доменных событий в UserService::getById, то ничего страшного не произойдет, страница с информацией о пользователе просто никак не будет реагировать на события входа и выхода на сайт.

Не приведет ли это к аду, когда новое доменное событие требуется проанализировать, каким UI экранам оно может быть интересно и соответственно внести обработку этого нового доменного события в различные методы различных сервисов? Может быть есть какие-то другие решения уведмолять UI об изменившихся данных?
модуль User ничего не знает о веб-сокетах. Его задача выкинуть события наружу. А снаружи хочешь подбирай их, хочешь не подбирай.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

У меня весь бекенд приложения асинхронный он полностью написан на ноде. Я планировал подбирать события в application layer, в сервисах. Там решается вопрос с тем, каким пользователям отправить событие. Затем управление передается инфраструктурному сервису, который уже непосредственно делает броадкаст события в нужные сокеты. Нормально это?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Domain events и websocket

Сообщение zelenin »

sda писал(а):У меня весь бекенд приложения асинхронный он полностью написан на ноде. Я планировал подбирать события в application layer, в сервисах. Там решается вопрос с тем, каким пользователям отправить событие. Затем управление передается инфраструктурному сервису, который уже непосредственно делает броадкаст события в нужные сокеты. Нормально это?
нормально
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

Что-то не пойму где регистрировать подписчиков событий. Вон вернон в своей книге делает это в методе аппликейшн сервиса, до вызова метода доменного объекта. Это не подходит для приложения, которое запущенно как демон. Для такого приложения всех подписчиков нужно зарегистировать только один раз. Где это делать?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Domain events и websocket

Сообщение zelenin »

sda писал(а):Что-то не пойму где регистрировать подписчиков событий. Вон вернон в своей книге делает это в методе аппликейшн сервиса, до вызова метода доменного объекта. Это не подходит для приложения, которое запущенно как демон. Для такого приложения всех подписчиков нужно зарегистировать только один раз. Где это делать?
в любом bootstrap-файле (файле, который запускается в любом инстансе приложения). Но вообще мне очевидно, что это должно происходить в конфиге приложения и собираться во время запуска.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

Про bootstrap файл понял, а про конфиг приложения не очень. Имеется ввиду хранить в конфиге путь где лежат подписчики, а затем в bootstrap файле загружать и регистировать всех подписчиков, которые располагаются по этому пути?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Domain events и websocket

Сообщение zelenin »

sda писал(а):Про bootstrap файл понял, а про конфиг приложения не очень. Имеется ввиду хранить в конфиге путь где лежат подписчики, а затем в bootstrap файле загружать и регистировать всех подписчиков, которые располагаются по этому пути?
это все зависит от вашего event manager'а.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

Еще такая проблема. В UI бывает, что на 1 событие нужно обновить данные в нескольких местах. Например если кто-то меняет логин, нужно его обновить в нескольких местах. Если этот юзер есть в чате то поменять ему логин в чате, если он сидит за покерным столом также поменять ему логин в покерном столе и т.д. Данные о том, кто в чате и кто за покерным столом являются разными экзеплярами данных. Поэтому обновлять нужно в нескольких местах.

Я планировал использовать Redux для изменения состояния приложения. Каждое событие, которое упало с сервера в UI я планировал трансформировать в экшен редакса. Затем те редьюсеры кому интересно событие обрабатывают экшен и изменяют свою часть общего состояния приложения. Таким образом, изменение логина произойдет в нескольких различных частях состояния приложения и изменения будут отображены во вью.

Это нормальное решение?
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

как сделать, чтобы domain events выбрасывались после сохранения агрегата?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain events и websocket

Сообщение ElisDN »

sda писал(а):как сделать, чтобы domain events выбрасывались после сохранения агрегата?
Через $this->recordEvent(new Event(...)) в агрегате и $aggregate->releaseEvents() после сохранения.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

ElisDN примерно такой же подход нашел здесь https://lostechies.com/jimmybogard/2014 ... s-pattern/
Вроде самое адекватное решение из всех, которые видел. Но получается придется научить репозиторий репозиторий как-то отбрасывать свойство агрегата в котором хранятся события, чтобы он его в базу не сохранял.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Domain events и websocket

Сообщение zelenin »

sda писал(а):ElisDN примерно такой же подход нашел здесь https://lostechies.com/jimmybogard/2014 ... s-pattern/
Вроде самое адекватное решение из всех, которые видел. Но получается придется научить репозиторий репозиторий как-то отбрасывать свойство агрегата в котором хранятся события, чтобы он его в базу не сохранял.
не надо было репозиторий этому учить изначально.

http://www.yiiframework.ru/forum/viewto ... 46#p203985
http://www.yiiframework.ru/forum/viewto ... 46#p204421
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

Ну хорошо. А что по поводу доменного события, которое возникает при создании нового доменного объекта ? Если выбрасывать его в конструкторе, то это событие будет возникать не только при создании нового объекта, но и при восстановлении объекта из базы тоже. Я пока думаю, что доменный сервис этого самое наилучшее решение, чтобы решить эту проблему. Что скажете?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain events и websocket

Сообщение ElisDN »

sda писал(а):...но и при восстановлении объекта из базы тоже.
Для восстановления из базы используйте рефлексию.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Domain events и websocket

Сообщение samdark »

И в этом топике дам ссылку на https://github.com/samdark/hydrator ...
Melodic
Сообщения: 87
Зарегистрирован: 2016.05.11, 17:43
Откуда: Луганск

Re: Domain events и websocket

Сообщение Melodic »

Sam Dark писал(а):И в этом топике дам ссылку на https://github.com/samdark/hydrator...
точки к ссылке прилипли
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Domain events и websocket

Сообщение samdark »

Отлепил.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain events и websocket

Сообщение sda »

ElisDN писал(а):
sda писал(а):...но и при восстановлении объекта из базы тоже.
Для восстановления из базы используйте рефлексию.
Ну в php ок, есть решение http://php.net/manual/en/reflectionclas ... ructor.php
А в javascript как лучше? Там у рефлекшена таких фишек нет.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Domain events и websocket

Сообщение zelenin »

sda писал(а):
ElisDN писал(а):
sda писал(а):...но и при восстановлении объекта из базы тоже.
Для восстановления из базы используйте рефлексию.
Ну в php ок, есть решение http://php.net/manual/en/reflectionclas ... ructor.php
А в javascript как лучше? Там у рефлекшена таких фишек нет.
без рефлексии есть практика создавать отдельный метод для восстановления из базы.
Ответить