Архитектурные основы

2 мин чтения ·

Hexagonal Architecture: бизнес-правила не должны жить в базе данных

Поменяли платёжного провайдера — сломали расчёт скидки. Когда полезно держать бизнес-логику независимо от инфраструктуры.

Компания меняет платёжного провайдера. Команда ожидала заменить интеграцию, но обнаружила, что в обработчике внешнего API заодно живут правила расчёта скидок, порядок подтверждения заказа и часть логики возврата. В результате техническая замена превращается в продуктовый риск.

Hexagonal Architecture, или Ports & Adapters, пытается убрать эту зависимость. В центре находятся бизнес-правила, а база данных, HTTP, очереди и внешние партнёры подключаются через заранее определённые границы.

Что на самом деле означает порт

Порт — это контракт взаимодействия, выраженный с точки зрения потребностей приложения. Например, бизнес-сценарию нужно «провести оплату» или «сохранить заказ». Он не обязан знать HTTP-адрес провайдера, имя таблицы или детали SDK.

Адаптер реализует контракт для конкретной технологии. Сегодня это один платёжный сервис, завтра другой. Входным адаптером может быть веб-API, фоновая задача или обработчик сообщения, но правила согласования заказа не должны переписываться из-за способа запуска.

Главное — направление зависимостей: технические детали зависят от внутренних контрактов, а не бизнес-правила от случайных деталей инфраструктуры.

Где компания получает реальную гибкость

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

Но это не гарантия мгновенной замены базы или провайдера. Новый партнёр может иметь другой смысл операций, ограничения возвратов или модель ошибок. Нужен адаптер, а иногда и пересмотр бизнес-договорённостей. Архитектура уменьшает связанность, но не отменяет различия продуктов.

Сколько интерфейсов достаточно

Соблазн создать порт для каждого метода велик. Тогда вместо понятной системы появляется коллекция одноразовых интерфейсов, через которые код передаёт те же аргументы. Команда платит временем за независимость, которой не пользуется.

Я бы выделял порты там, где действительно существуют разные причины изменения или значимая внешняя зависимость. Простые внутренние вычисления не обязаны иметь адаптер только потому, что паттерн нарисован шестиугольником.

Проверка перед внедрением

Попросите команду показать два сценария: как проверить бизнес-правило без внешней инфраструктуры и сколько кода изменится при замене интеграции. Если оба сценария уже просты, большая перестройка может быть ненужной.

Если границы расплывчаты, полезнее сначала выявить бизнес-операции и ответственность модулей, чем начать с генерации файлов. Слои приложения могут помочь, но сами по себе не гарантируют нужное направление зависимостей.

Ports & Adapters оправданы, когда бизнес-правила должны жить дольше выбранной сегодня инфраструктуры. Ради этого стоит делать явные границы, но не создавать абстракции на всякий случай.