Что такое Onion Architecture (Луковая архитектура)?

Ответ

Onion Architecture — это архитектурный паттерн, основанный на принципах чистой архитектуры и зависимостей, направленных внутрь. Бизнес-логика (ядро) изолирована от внешних деталей (UI, БД, фреймворков).

Ключевые слои (от центра к периферии):

  1. Domain Model (Ядро): Содержит сущности и бизнес-правила. Не зависит ни от чего.
  2. Application Services (Слой приложения): Оркестрирует выполнение use-cases, координируя домен и внешний мир.
  3. Infrastructure (Инфраструктура): Реализует технические детали: репозитории (доступ к данным), внешние API, логирование.
  4. Presentation (Представление): Контроллеры, UI, API-ендпоинты.

Главный принцип: Внешние слои зависят от внутренних, но не наоборот. Это достигается за счёт инверсии зависимостей (DIP).

Пример структуры на Java:

// 1. DOMAIN LAYER (Ядро) - НЕТ зависимостей от фреймворков
public class Order {
    private Long id;
    private Money total;
    public boolean isValid() { /* бизнес-правило */ }
}
public interface OrderRepository { // Абстракция в ядре
    Order findById(OrderId id);
}

// 2. APPLICATION LAYER
public class OrderService {
    private final OrderRepository repository; // Зависимость от абстракции
    public Order getOrder(OrderId id) {
        return repository.findById(id);
    }
}

// 3. INFRASTRUCTURE LAYER - реализует абстракции ядра
@Repository
public class JpaOrderRepository implements OrderRepository {
    @Override
    public Order findById(OrderId id) {
        // JPA-специфичный код
    }
}

Преимущества:

  • Тестируемость: Ядро можно тестировать без фреймворков и БД.
  • Гибкость: Замена базы данных или UI не затрагивает бизнес-логику.
  • Сохранность: Бизнес-правила защищены от изменений во внешних слоях.

Ответ 18+ 🔞

А, Onion Architecture, говоришь? Ну это ж классика, блядь, как "Муму" Тургенева, только для кода! Сейчас разложу по полочкам, чтобы даже мартышлюшка с гитарой поняла.

Представь себе луковицу, сука. Не Чиполлино, а нормальную, русскую, чтоб до слёз пробирала. В самом центре, под всеми слоями — святая святых, ядро (Domain Model). Там живут твои главные сущности и бизнес-правила. Это как Герасим, блядь — здоровый, немой мужик с железной логикой. Он нихуя не знает про то, что там снаружи: Spring, базы данных, веб-сервера — ему похуй. Он знает, что заказ должен быть валидным, и всё. Абсолютная независимость, ёпта!

// Вот он, Герасим нашего приложения. Никаких @Entity, только хардкор.
public class Order {
    private Long id;
    private Money total;
    public boolean isValid() { /* Вот это бизнес-правило, блядь! */ }
}

Дальше идёт слой приложения (Application Services). Это уже не Герасим, а такой управляющий, который оркестрирует всё это безобразие. Он знает, что нужно "получить заказ", но сам-то он в базу не лезет, нет. Он орет в пустоту: "Эй, кто там реализует OrderRepository? Подать сюда заказ!". Он зависит от абстракций ядра, а не от конкретной реализации. Умный, блядь, не то что некоторые.

// Управляющий, который знает, кого позвать, но сам нихуя не делает.
public class OrderService {
    private final OrderRepository repository; // Смотрит на интерфейс из ядра!
    public Order getOrder(OrderId id) {
        return repository.findById(id); // "Муму! Принеси заказ!"
    }
}

А теперь, внимание, пиздец, где собака порылась! Инфраструктурный слой (Infrastructure). Это уже нанятые работяги, которые реально пашут. Вот этот чувак JpaOrderRepository — он знает всю подноготную JPA, Hibernate и прочую хуйню. Он реализует тот самый интерфейс OrderRepository, который объявили в ядре. Он зависит от ядра, а не наоборот! Ядро про него не знает ни хуя. Это и есть инверсия зависимостей — внешнее подстраивается под внутреннее, а не наоборот, как у нормальных людей.

// Работяга, который знает, как ебаться с базой.
@Repository
public class JpaOrderRepository implements OrderRepository { // Смотри-ка, реализует интерфейс ядра!
    @Override
    public Order findById(OrderId id) {
        // А тут уже вся JPA-магия, entityManager'ы и прочий шаманский код.
        // Ядру на это похуй с высокой колокольни.
    }
}

Ну и сверху, как пёстрая тряпка, слой представления (Presentation) — контроллеры, API, UI. Они просто кричат в сервисный слой: "Эй, дай-ка сюда заказ номер 42!".

И в чём, блядь, соль, спросишь ты? А соль, Колян, в том, что:

  • Тестируемость — овердохуищная. Ты можешь тестировать своего Герасима (ядро) вообще без базы, без Spring, на голых моках. Просто подсовываешь ему заглушку вместо репозитория и смотришь, как он свои правила выполняет. Красота, блядь!
  • Гибкость — хоть обосрись. Надоел тебе Hibernate? Хочешь на MongoDB переехать или, хуле, на файлы текстовые? Да похуй! Пишешь новую реализацию MongoOrderRepository, которая тоже implements OrderRepository, подменяешь в конфиге — и ядро даже не чихнёт. Оно нихуя не заметило.
  • Сохранность. Бизнес-логика заперта в центре, как в крепости. Эти фронтендеры-распиздяи со своими новыми фреймворками могут менять UI каждый месяц, а твои правила "что такое валидный заказ" останутся неприкосновенными. Никакой внешний пиздец до них не доберётся.

Вот и вся философия. Не тащи зависимости внутрь, а выноси реализацию наружу. Чтобы ядро было чистым, как слеза младенца, и независимым, как тот самый Герасим. А то ведь бывает — намешают в коде Spring, Hibernate, Kafka в одном флаконе, а потом думают: "И как это, сука, тестировать?". Да никак, блядь! Накрылся медным тазом проект. Onion Architecture от таких распиздяйств и спасает.