Книга «Паттерны разработки на Python: TDD, DDD и событийно-ориентированная архитектура»

Гарри Персиваль и Боб Грегори познакомят вас с проверенными паттернами, чтобы каждый питонист мог управлять сложностью приложений и получать максимальную отдачу от тестов. Теория подкреплена примерами на чистом Python, лишенном синтаксической избыточности Java и C#.

В этой книге:

  • «Инверсия зависимостей» и ее связи с портами и адаптерами (гексагональная/чистая архитектура).
  • Различия между паттернами «Сущность», «Объект-значение» и «Агрегат» в рамках DDD.
  • Паттерны «Репозиторий» и UoW, обеспечивающие постоянство хранения данных.
  • Паттерны «Событие», «Команда» и «Шина сообщений».
  • Разделение ответственности на команды и запросы (CQRS).
  • Событийно-управляемая архитектура и реактивные расширения.
  • Команды и обработчик команд

    В предыдущей главе мы говорили об использовании событий как способа представления данных на входе в систему. Мы превратили наше приложение в машину для обработки сообщений.

    Ради этого мы преобразовали все функции варианта использования в обработчики событий. Когда API получает POST для создания новой партии товара, он создает новое событие BatchCreated и обрабатывает его так, как если бы это было внутреннее событие. Это может показаться нелогичным. В конце концов, партия товара еще не создана, именно поэтому мы и вызывали API. Мы собираемся исправить этот концептуальный недостаток с помощью ввода команд и покажем, как они могут обрабатываться одной и той же шиной сообщений по другим правилами.

    Код для этой главы находится в ветке chapter_10_commands на GitHub:

    Команды и события

    Подобно событиям, команды представляют собой тип сообщений — инструкции, посылаемые одной частью системы другой. Мы обычно представляем команды немыми структурами данных и можем обрабатывать их почти так же, как события.

    Но различия между командами и событиями очень важны.

    Команды посылаются одним актором другому конкретному актору в надежде, что в результате произойдет то или иное событие. Когда мы отправляем форму в обработчик API, то посылаем команду. Командам даются имена в форме глаголов повелительного наклонения вроде «allocate stock» («разместить товарный запас») или «delay shipment» («задержать поставку»).

    Команды улавливают намерение (intent). Они выражают то, чего мы хотим от системы. Когда команды не выполняются, отправитель в результате должен получить информацию об ошибке.

    Акторы транслируют события всем заинтересованным слушателям (listeners). Когда мы публикуем событие BatchQuantityChanged, то не знаем, кто его подхватит. Событиям даются имена в форме глаголов прошедшего времени или причастных оборотов вроде «order allocated to stock» («заказ размещен в товарном запасе») или «shipment delayed» («отгрузка задержана»).

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

    События улавливают факты о том, что происходило в прошлом. Поскольку мы не знаем, кто будет обрабатывать событие, отправителей не должно волновать, удалось получателям выполнить команду или нет. В табл. 10.1 сравниваются события и команды.

    Какие команды сейчас есть в нашей системе?

    Вытаскиваем несколько команд (src/allocation/domain/commands.py)

    1commands.Allocate заменит events.AllocationRequired.
    2commands.CreateBatch заменит events.BatchCreated.
    3commands.ChangeBatchQuantity заменит events.BatchQuantityChanged.

    Различия в обработке исключений


    Замена имен и глаголов — это прекрасно, но жонглирование словами не поменяет поведение системы. Мы хотим обращаться с событиями почти так же, как с командами, но не одинаково. Давайте посмотрим, как изменяется шина сообщений.

    Направляем события и команды по-разному (src/allocation/service_layer/messagebus.py)

    1 У нее все еще есть основная точка входа handle(), принимающая message — команду либо событие.
    2 Мы отправляем события и команды двум разным вспомогательным функциям, которые показаны ниже.

    Вот как происходит работа с событиями:

    События не могут прервать поток (src/allocation/service_layer/messagebus.py)

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

    И вот как выполняются команды:

    Команды заново инициируют исключения (src/allocation/service_layer/messagebus.py)

    1 Диспетчер команд ожидает, что для каждой команды будет лишь один обработчик.
    2 Если инициируются какие-либо ошибки, то они быстро останавливают работу и потом всплывают.
    3 Инструкция return result с нами ненадолго; как уже упоминалось в подразделе «Уродливый костыль: шине сообщений приходится возвращать результаты» на с. 189, это костыль, позволяющий шине сообщений возвращать ссылку на партию товара, чтобы API мог его использовать. Мы исправим это в главе 12.

    Мы также заменяем единый словарь HANDLERS разными словарями для команд и событий. По соглашению команды могут иметь только один обработчик.

    Новые словари с обработчиками (src/allocation/service_layer/messagebus.py)

    С полным содержанием статьи можно ознакомиться на сайте “Хабрахабр”:

    https://habr.com/ru/company/piter/blog/588060/

    Источник



    Leave A Reply

    Your email address will not be published.