Шаг 1: касса зовёт всех сама
Исходный код:
Checkoutсохраняет заказ и по очереди вызывает склад, аналитику и почту.
Урок: События вместо прямых вызовов. Следующий шаг: доменное событие и синхронный диспетчер.
Что было
Checkout получает в конструкторе Orders, Warehouse, Analytics и Mailer. Метод place кладёт заказ в Orders, потом вызывает requestPicking склада, track("order_placed", ...) аналитики и send почты. Порядок жёсткий: склад, аналитика, почта.
Все три сервиса в уроке - фейки: они складывают вызовы в списки picking, events и sent, по которым тесты проверяют результат. У Analytics есть флаг down: внешний сервис лежит, и track бросает ошибку "analytics is down" (в Go возвращает ErrAnalyticsDown).
Что меняем
Пока ничего. Это точка отсчёта: тесты фиксируют поведение, которое дальше будет держать рефакторинг.
Первый тест проверяет обычное оформление: заказ сохранён, сборка запрошена, событие в аналитике, письмо ушло. Второй честно записывает то, что болит: при лежащей аналитике place падает, заказ при этом уже сохранён, склад уже получил запрос, а письма нет. Это не желаемое поведение, а текущее, и тест нужен, чтобы на шаге 3 изменение было видно в коде теста, а не только в тексте.
Как это собирается
Фейки создаются там, где в приложении были бы настоящие клиенты (контейнер, main), и все четыре объекта передаются в конструктор Checkout. Пример оформляет два заказа, между ними аналитика ложится. Первый заказ проходит целиком. Второй падает: склад его соберёт, но письма покупатель не получит, а вызывающий код видит ошибку.
Сценарий целиком с выводом: пример на PHP, он же на Go, Python и TypeScript в панели кода.
Что стало лучше
Ничего, но кое-что здесь честно хорошо: вся последовательность видна в пяти строках place, а порядок вызовов очевиден. Если реакция одна и важна для самой операции, прямой вызов - правильный выбор.
Что ещё болит
Checkoutзнает обо всех, кто реагирует на заказ. Добавить бонусные баллы - правка кассы, её конструктора и всех мест, где она собирается.- Тест оформления обязан собрать почту, склад и аналитику, даже если проверяет что-то одно.
- Самая неважная реакция ломает самую важную: лежит аналитика - нет письма, а
placeсообщает об ошибке, хотя заказ сохранён. - Порядок реакций зашит в код и влияет на результат: поставь почту перед аналитикой, и сбой выглядел бы иначе.
Запуск: make test T=lessons/003-events-instead-of-calls/step-1