Существуют некоторые различия в реализации, в зависимости от того, используете ли вы программирование на основе стека вызовов или, например, модель актора.
Далее я расскажу о случае, наиболее близком к DDD и части "C" в CQRS: внесение изменений в состояние системы. Часть «Q» проще со стороны Hexagon: ее сложность в основном на стороне адаптера.
Что касается меня, я поместил словарь в ядро шестиугольника. Он сопоставляется с моделью DDD Ubiquitous Language и состоит из неизменных структур данных с проверкой бизнес-инвариантов этих структур данных.
Далее, есть точка принятия решения. Когда вы принимаете решение, в соответствии с принципом единой ответственности, вы должны делать только это. Не делать внешние вызовы, ввод-вывод и т. Д. Итак, вам нужна некоторая информация, чтобы принять решение. Когда эта информация собрана, она может быть помещена в объект Command. Вы передаете его лицу, принимающему решение, которое приблизительно сопоставляется с агрегатом DDD. Затем он либо утверждает команду и создает событие или набор изменений (независимо от того, делаете ли вы EventSourcing или нет), либо отклоняется. Без каких-либо внешних звонков. То есть он не использует порты Hexagon.
Внутри шестиугольника остается логика для сбора внешних данных, вызова лица, принимающего решения, и обработки результата. Эта логика может быть смоделирована как простой конечный автомат и проверено модулем. Это то, что я называю прецедентом в моем шестиугольнике. Потому что именно здесь координируются потоки данных между портами и лицами, принимающими решения. Итак, в прецеденте используются порты.
Экземпляр варианта использования создается при получении бизнес-запроса на основной порт Hexagon. Есть FSM и исполнитель UseCase, который фактически вызывает вторичные порты, получает их ответы и продвигает сценарий использования FSM.
Поток обработки сценария использования может состоять из следующих шагов:
- Подтвердить полученный бизнес-запрос
- Если неверно - отформатировать бизнес-ответ с ошибкой
- Если действует - подготовить запросы к вторичным портам
- Отправить подготовленные запросы
- Получение ответов вторичных портов
- В случае сбоя или тайм-аута - отформатировать бизнес-ответ с ошибкой
- Если данные собраны успешно, подготовьте Команду для лица, принимающего решение
- Позвоните лицу, принимающему решение, и верните Событие / Изменения / Отказ
- В случае отклонения - отформатировать бизнес-запрос с ошибкой
- Если принято - подготовить другой набор запросов для вторичных портов для выполнения решения: сохранить в БД, отправить в MQ, запустить ракеты и т. Д.
- Ожидание выполнения запросов по вторичным портам
- Если не удалось - отформатируйте бизнес-ответ с ошибкой
- Если все в порядке - форматировать бизнес-ответ с успехом
Итак, вариант использования определенно принадлежит домену, так как он зависит не от реализаций адаптеров, а от их интерфейсов. И это формирует прикладной уровень Домена.
Полезно поместить вариант использования в отдельный фрагмент кода, потому что таким образом у этого кода будет одна причина для изменения - если, конечно, вариант использования изменится. Он отличается от логики принятия решений или от логики валидации значений домена.