Clean Architecture, Onion, Hexagonal (Ports & Adapters)

↑ 8.2 Архитектурные стили и DDD · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: senior

Зачем это на собесе

Ждут объяснения «правила зависимостей» и как это выглядит в .NET-проекте.

Объяснение

Общая идея трёх стилей: бизнес-логика в центре и ни от чего не зависит; инфраструктура (БД, HTTP, брокер) зависит от неё через интерфейсы.

flowchart TB
  subgraph Внешний[Внешний слой]
    API[Web API / UI]
    INF[Infrastructure: EF, Kafka, HTTP-клиенты]
  end
  subgraph App[Application: use cases, порты]
  end
  subgraph Domain[Domain: сущности, правила]
  end
  API --> App
  INF --> App
  App --> Domain
СтильФормулировка
Hexagonal (Ports & Adapters, Cockburn)ядро определяет порты (интерфейсы); адаптеры (HTTP, БД) реализуют их
Onion (Palermo)концентрические слои, зависимости внутрь
Clean (Martin)Entities → Use Cases → Interface Adapters → Frameworks; Dependency Rule

Структура решения .NET:

src/
  Orders.Domain/          # сущности, value objects, доменные события; без зависимостей
  Orders.Application/     # use cases (команды/запросы), порты: IOrderRepository, IPaymentGateway
  Orders.Infrastructure/  # EF Core, репозитории, клиенты, брокер — реализует порты
  Orders.Api/             # контроллеры/endpoint-ы, композиционный корень (DI)
tests/

Правила: Domain ни от кого не зависит; Application зависит от Domain; Infrastructure и Api — от Application. Приложение собирается в Api (composition root).

Нюансы и подводные камни

  • Для простого CRUD избыточно: 4 проекта ради GET/POST.
  • Формальное разделение без поведения в домене — анемичная модель в красивой обёртке.
  • Протекание: сущности EF с атрибутами и virtual-навигациями просачиваются в домен — решайте осознанно.
  • Интерфейс ради интерфейса: порт нужен на границе с внешним миром, а не для каждого класса.
  • Проверяйте зависимости архитектурными тестами.

Практика

  1. Разнесите небольшое приложение на Domain/Application/Infrastructure/Api.
  2. Добавьте архитектурный тест, запрещающий зависимость Domain от Infrastructure.
  3. Замените адаптер (in-memory вместо БД) в тестах Application.

Вопросы с ответами

Связанные темы