Шаг 2: доменное событие и синхронный диспетчер
CheckoutпубликуетOrderPlaced, а склад, аналитика и почта подписываются на него сами.
Урок: События вместо прямых вызовов. Предыдущий шаг: касса зовёт всех сама. Следующий шаг: независимые подписчики.
Что было
Checkout получал три сервиса и вызывал их по очереди. Касса знала обо всех реакциях, а тест оформления собирал их все.
Что меняем
- Появляется событие
OrderPlaced: неизменяемый факт в прошедшем времени с номером заказа, почтой, товарами и суммой. Слушателю хватает данных события, ему не нужно спрашивать кассу. - Появляется
EventDispatcherс двумя методами:subscribe(тип события, слушатель) иdispatch(событие). Диспетчер синхронный: зовёт слушателей по очереди в том же процессе. - Каждая реакция становится слушателем:
RequestPicking,TrackPurchase,SendConfirmation. Это маленькие объекты, которые получают свой сервис и знают, что сделать с событием. Checkoutполучает толькоOrdersи диспетчер.placeсохраняет заказ и публикует событие.
Тесты не меняются по смыслу: меняется только сборка в setUp, где появляются три подписки. Тест с лежащей аналитикой проходит как раньше - ошибка долетает до place, письма нет. Добавлен тест, что касса работает с диспетчером без подписчиков: ей больше не нужна почта, чтобы оформить заказ.
Как это собирается
Подписки переезжают из кассы в место сборки приложения: в PHP это сервис-провайдер, в Go - main, в Python и TypeScript - модуль старта. Там создаются клиенты, из них слушатели, и каждый подписывается на OrderPlaced. Касса получает готовый диспетчер и не знает, сколько у него подписчиков. Вывод примера такой же, как на шаге 1: второй заказ без письма и с ошибкой.
Сценарий целиком с выводом: пример на PHP, он же на Go, Python и TypeScript в панели кода.
Что стало лучше
Checkoutне знает о почте, складе и аналитике. Новая реакция - новый слушатель и строка подписки, касса не меняется.- Каждую реакцию можно проверить отдельно: дать слушателю событие и посмотреть на его сервис.
- Событие - явный контракт между оформлением и реакциями. Его поля видно в одном месте.
Что ещё болит
- Ошибка слушателя прерывает
dispatchи долетает доplace. Лежит аналитика - письма по-прежнему нет. - Слушатели зависят от порядка подписки: если подписать почту раньше аналитики, письмо уйдёт. Независимыми они только выглядят.
- Вызывающий код получает ошибку чужой реакции и не может понять, оформлен заказ или нет.
Запуск: make test T=lessons/003-events-instead-of-calls/step-2