Clean Architecture, Onion, Hexagonal (Ports & Adapters)
↑ 8.2 Архитектурные стили и DDD · ← Предыдущая · → Следующая
Зачем это на собесе
Ждут объяснения «правила зависимостей» и как это выглядит в .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-навигациями просачиваются в домен — решайте осознанно. - Интерфейс ради интерфейса: порт нужен на границе с внешним миром, а не для каждого класса.
- Проверяйте зависимости архитектурными тестами.
Практика
- Разнесите небольшое приложение на Domain/Application/Infrastructure/Api.
- Добавьте архитектурный тест, запрещающий зависимость Domain от Infrastructure.
- Замените адаптер (in-memory вместо БД) в тестах Application.
Вопросы с ответами
В чём суть Dependency Rule?
Зависимости в исходном коде направлены только внутрь, к домену; внутренние слои ничего не знают о внешних.
Что такое порты и адаптеры?
Порт — интерфейс, определяемый ядром; адаптер — его реализация для конкретной технологии.