Domain Driven Design и модульный монолит в Python
Методология DDD структурирует архитектуру в Python за счет четкого разделения логики на ограниченные контексты и строгие внутренние слои domain, application и infrastructure. Каждый автономный модуль соответствует выделенному домену, сохраняя независимость бизнес-правил от баз данных, сетевых фреймворков и внешних протоколов. Надежная чистая архитектура ddd в python опирается на строгие интерфейсы, которые изолируют зависимости пакетов и передают управление через внутрипроцессные события.
событиями в памяти процесса
без сторонних фреймворков
при модульной изоляции
для изолированных доменов
Разделение кодовой базы на слои domain, application и infrastructure
Язык Python традиционно славится своей гибкостью и простотой старта. Однако эта же свобода таит в себе коварную ловушку при росте кодовой базы. Инженерная интуиция часто толкает команды складывать все модели данных в один общий пакет, а сервисные функции - в другой. В результате кодовая база превращается в труднораспутываемый клубок взаимных импортов. Если честно, динамическая природа Python способна жестоко наказать за отсутствие системной дисциплины в организации каталогов.
Решение предлагает предметно-ориентированный подход, в котором монолит разделяют на изолированные модули по бизнес-доменам. Внутри каждого доменного модуля инженеры выделяют три фундаментальных слоя: domain, application и infrastructure. Слой domain инкапсулирует чистую бизнес-логику: сущности, объекты-значения и правила предметной области. Этот слой свободен от внешних библиотек и фреймворков.
Слой application реализует пользовательские сценарии и координирует выполнение операций. Он вызывает доменные сущности, управляет транзакциями и определяет абстрактные интерфейсы репозиториев. Слой infrastructure содержит конкретные технические детали: адаптеры баз данных, сетевые клиенты и интеграции со сторонними сервисами. Направление зависимостей всегда строго направлено внутрь: инфраструктура знает о домене, но домен ничего не знает об инфраструктуре.
Использование аннотаций типов, dataclasses и Pydantic для описания доменных моделей
Парадокс современного Python заключается в том, что строгая статическая типизация превратилась из объекта насмешек в фундамент корпоративной надежности. Для описания доменных сущностей и неизменяемых объектов-значений идеально подходят стандартные Python dataclasses. За счет декоратора frozen разработчик гарантирует неизменяемость доменного объекта и защищает систему от случайных мутаций состояния в соседних методах.
При этом валидацию входных данных на границах модуля эффективно выполняет библиотека Pydantic. Важно соблюдать границу ответственности: схемы Pydantic проверяют внешние полезные нагрузки на уровне контроллеров и фасадов, после чего преобразуются в чистые доменные сущности. Попытка использовать модели Pydantic или ORM-сущности прямо в ядре домена часто приводит к протеканию технических деталей сериализации в бизнес-правила. В реальности доменное ядро должно оперировать только понятиями предметной области.
Изоляция взаимодействия с базой данных SQLAlchemy внутри отдельных доменных модулей
Связывание доменных моделей с таблицами реляционной базы данных долгое время считалось неизбежным компромиссом. Классический шаблон Active Record намертво привязывает бизнес-логику к соединению с базой данных. В модульном монолите такой подход недопустим: модуль теряет автономность, а модульные тесты требуют обязательного запуска экземпляра PostgreSQL.
Инженеры применяют паттерн Data Mapper с помощью декларативных отображений в SQLAlchemy. Таблицы и модели ORM объявляют исключительно внутри слоя infrastructure конкретного модуля. Репозиторий извлекает данные из базы, отображает строки таблиц в чистые сущности dataclasses и возвращает их в слой application. Доменные сущности ничего не знают о существовании внешних ключей, индексов или сессий базы данных. Это позволяет тестировать сложнейшую бизнес-логику с помощью мгновенных unit-тестов в оперативной памяти.
Реализация внутрипроцессной шины событий для взаимодействия модулей
Каким образом модули обмениваются информацией, если прямые импорты чужих классов строго запрещены? Самый быстрый способ разрушить модульность - вызвать метод внутреннего сервиса соседнего домена напрямую. Чтобы избежать жесткой сцепленности, команды внедряют легковесную внутрипроцессную шину событий.
Когда в модуле заказов происходит оплата счета, модуль не вызывает сервис складского учета напрямую. Вместо этого он генерирует событие факта OrderPaidEvent и публикует его в локальную шину. Модуль склада подписывается на данное событие через свой слушатель и запускает внутренний процесс резервирования товаров. Платформа ShelfMC поддерживает доменный подход, предоставляя готовую основу для построения автономных модулей с надежными интерфейсами взаимодействия. При этом ShelfMC стандартизирует структуру Python-модулей, сокращая время вывода новых сервисов в промышленную эксплуатацию.