В классической трёхслойной архитектуре слои идут сверху вниз: UI → бизнес-логика → слой доступа к данным. Зависимости направлены вниз: бизнес-логика зависит от слоя данных, тот — от базы. В итоге домен намертво сцеплен с конкретной СУБД и фреймворком: нельзя протестировать логику без поднятой базы, а смена хранилища тянет правки в бизнес-код. Луковая архитектура (Onion) переворачивает это: в центре — чистый домен, а всё инфраструктурное вынесено наружу и зависит от центра, а не наоборот.
Что такое луковая архитектура
Представьте луковицу в разрезе: концентрические кольца, в самом центре — доменная модель. Каждое кольцо может зависеть только от колец, которые внутри него. Внешние кольца знают о внутренних, а внутренние о внешних — нет.
Что на схеме: стрелки зависимостей идут только внутрь, к домену.
Кольца от центра наружу:
- Доменная модель — сущности и value-объекты с бизнес-правилами. Чистый код: никаких импортов БД, HTTP, фреймворка.
- Доменные сервисы — логика, которая охватывает несколько сущностей и не помещается в одну.
- Сервисы приложения (use cases) — оркестрация: принять запрос, дёрнуть домен, сохранить результат.
- Внешнее кольцо — всё остальное: база, очереди, внешние API, веб-контроллеры, конфигурация фреймворка.
Правило зависимостей
Главное правило одно: зависимости направлены только внутрь. Внешнее кольцо знает о внутренних, внутренние о внешнем — нет.
Как это возможно технически, ведь сервису приложения нужно сохранить данные в базу (внешнее кольцо)? Через инверсию зависимостей: внутреннее кольцо объявляет интерфейс (например OrderRepository), а внешнее кольцо его реализует (PostgresOrderRepository). Домен зависит от интерфейса, который сам же и определил; конкретная реализация живёт снаружи и подставляется при сборке приложения. Так стрелка зависимости разворачивается внутрь, хотя поток данных идёт наружу.
Прямое следствие — домен тестируется без базы и фреймворка: интерфейсы подменяются заглушками.
Onion, гексагональная и Clean Architecture — одно семейство
Это все варианты одной идеи: держать домен чистым и развернуть зависимости к центру. Различается в основном словарь и акценты:
- Гексагональная (Ports & Adapters) — домен в центре, вокруг него порты (интерфейсы) и адаптеры (реализации). Подчёркивает симметрию входящих и исходящих границ.
- Луковая (Onion) — те же зависимости-внутрь, но поданы как концентрические кольца с доменной моделью в самом центре; акцент на слоистости.
- Clean Architecture — то же самое кольцами «entities → use cases → interface adapters → frameworks» с тем же правилом зависимостей.
На практике они взаимозаменяемы — выбирайте словарь, принятый в команде. На этом сайте подробно разобран гексагональный вариант (ядро, порты, адаптеры, тесты архитектуры) — если нужна реализация по шагам, начните с него.
Когда применять
Луковая архитектура оправдана, когда домен богатый и живёт долго, инфраструктур несколько (БД + очередь + внешние API), а тестируемость важна. Для простого CRUD-сервиса без сложных правил концентрические кольца — избыточная церемония: получится много интерфейсов ради одного-двух вызовов.
Коротко
- Луковая архитектура — концентрические кольца с доменной моделью в центре; зависимости направлены только внутрь.
- Домен не знает о базе, HTTP и фреймворке — снаружи подставляются реализации интерфейсов, объявленных внутри (инверсия зависимостей).
- Главный выигрыш — домен тестируется без инфраструктуры, а смена БД/фреймворка не задевает бизнес-логику.
- Onion, гексагональная и Clean Architecture — одно семейство; разница в словаре, не в сути.
- Для простого CRUD — избыточно; применяйте при богатом, долгоживущем домене.
Что почитать дальше
- Гексагональная архитектура — тот же принцип в варианте ports & adapters, с реализацией по шагам.
- CQRS — разделение команд и запросов поверх чистого домена.
- Domain-Driven Design — что именно живёт в центре луковицы.