Какие слои (layers) лучше всего выделить при проектировании приложения?

Ответ

Классическая многослойная архитектура (Layered или N-Tier) разделяет ответственность, упрощает поддержку и тестирование. Вот основные рекомендуемые слои:

  1. Presentation Layer (Слой представления). Отвечает за взаимодействие с пользователем или внешними системами.

    • Примеры: ASP.NET Core Controllers, MVC Views, Razor Pages, Web API Controllers, gRPC Services, Blazor Components.
    • Задача: Принимать запросы, валидировать входные данные, вызывать бизнес-логику и возвращать ответы.
  2. Application Layer (Слой приложения/Use Cases). Оркестрирует выполнение конкретных сценариев использования (use cases).

    • Примеры: Сервисы приложения (Application Services), MediatR Handlers, Command/Query объекты (CQRS).
    • Задача: Координировать работу доменного слоя и инфраструктуры для выполнения бизнес-транзакции. Не содержит сложной бизнес-логики.
      // Application Service (координатор)
      public class PlaceOrderService
      {
      private readonly IOrderRepository _repo;
      private readonly IPaymentGateway _gateway;
      public async Task Execute(PlaceOrderCommand command)
      {
          var order = new Order(command.Items); // Домен
          await _repo.Save(order);              // Инфраструктура
          await _gateway.Charge(order.Total);   // Инфраструктура
      }
      }
  3. Domain Layer (Доменный слой). Ядро приложения, содержащее бизнес-логику, правила и сущности.

    • Примеры: Сущности (Entities), Объекты-значения (Value Objects), Агрегаты (Aggregates), Доменные сервисы (Domain Services), Доменные события (Domain Events).
    • Задача: Инкапсулировать ключевые бизнес-правила. Этот слой не должен зависеть от других слоев.
  4. Infrastructure Layer (Инфраструктурный слой). Реализует технические детали доступа к внешним ресурсам.

    • Примеры: Репозитории (Repositories), доступ к БД (DbContext), вызов внешних API, отправка email, работа с файловой системой, кэширование.
    • Задача: Предоставлять абстракции (интерфейсы), которые определены в слоях выше (Application/Domain).

Ключевой принцип: Зависимости направлены внутрь, к доменному слою. Presentation → Application → Domain ← Infrastructure. Это обеспечивает тестируемость и независимость бизнес-логики от деталей реализации.

Ответ 18+ 🔞

Давай разберём эту многослойную архитектуру, как она есть, без прикрас. Представь, что ты строишь дом, но вместо гвоздей и молотка у тебя — абстракции и зависимости. И если накосячить, дом развалится, но не с грохотом, а тихо, в продакшене, в три часа ночи.

Слой 1: Представление (Presentation Layer) Это, по сути, лицо твоего приложения. Та часть, которую тыкают пользователи или другие сервисы. Веб-апи контроллеры, страницы Razor, вся эта хрень. Его задача — не умничать, а взять запрос, проверить, не прислали ли тебе хуйню вместо данных, позвать следующий слой и отдать ответ. Как швейцар в дорогом отеле: вежливый, но сам он тебе номер не уберёт и мини-бар не пополнит. Он просто передаст запрос дальше.

Слой 2: Слой приложения (Application Layer) Вот тут начинается магия оркестровки, или, как я это называю, слой «управляющего делами». У тебя есть конкретный сценарий: «оформить заказ». Этот слой — тот самый менеджер, который не пашет сам, а говорит: «Вася, создай заказ. Петя, сохрани его в базу. Система оплаты, списывай бабки». Сам он сложной логики не содержит, он просто знает, кого в какой последовательности дернуть. Часто это всякие ApplicationService или обработчики команд через MediatR. Если представить, что домен — это бригада строителей, то этот слой — прораб, который по бумажке координирует их работу.

// Это тот самый прораб (Application Service)
public class PlaceOrderService
{
    private readonly IOrderRepository _repo; // Это доступ к складу (инфраструктура)
    private readonly IPaymentGateway _gateway; // Это касса (инфраструктура)

    public async Task Execute(PlaceOrderCommand command)
    {
        // Говорит бригаде: "Собери заказ!" (Домен)
        var order = new Order(command.Items);
        // Кричит кладовщику: "Запакуй и на склад!" (Инфраструктура)
        await _repo.Save(order);
        // Орёт кассиру: "Стриги с клиента бабки!" (Инфраструктура)
        await _gateway.Charge(order.Total);
    }
}

Слой 3: Доменный слой (Domain Layer) А вот это уже святая святых, ядро, ради которого всё затевалось. Тут живут твои бизнес-сущности, правила и законы. «Заказ не может быть на отрицательную сумму», «Товара должно быть достаточно на складе», «Скидка применяется только если у клиента больше трёх покупок». Этот слой — как скелет и мозг приложения. Он не должен НИ ОТ КОГО зависеть. Ни от базы данных, ни от внешних апи, ни от фреймворка. Чистая бизнес-логика в вакууме. Сущности, агрегаты, доменные события — всё это инструменты, чтобы описать, как работает твой бизнес, а не твой код.

Слой 4: Инфраструктурный слой (Infrastructure Layer) Реальная, грубая жизнь. Всё, что связано с внешним миром: база данных, файловая система, отправка смс, запросы к платёжке, кэш в Redis. Этот слой — рабочие лошадки, которые реализуют те интерфейсы (абстракции), которые были объявлены в доменном или прикладном слое. Домен сказал: «Мне нужен репозиторий для сохранения заказов». Инфраструктура отвечает: «Без проблем, босс, вот тебе класс SqlOrderRepository, который лезет в SQL Server». Ключевой момент — зависимость идёт ОТ инфраструктуры К домену, а не наоборот.

Главный принцип, который надо выжечь себе на подкорке: Зависимости направлены внутрь, к центру, к домену. Представление зависит от прикладного слоя, прикладной слой зависит от домена, а инфраструктура — тоже зависит от домена (реализуя его абстракции). Получается такая картина: Presentation → Application → Domain ← Infrastructure.

Зачем этот геморрой? А затем, ёпта, что твоя бизнес-логика становится независимой. Хочешь сменить базу данных с MySQL на PostgreSQL? Меняй только инфраструктурный слой. Хочешь переехать с веб-апи на desktop-приложение? Лепи новое представление. А ядро, самые важные правила — они остаются нетронутыми и, что самое главное, легко тестируемыми. Ты можешь отъебать юнит-тестами весь свой домен, не поднимая базу данных и не запуская веб-сервер. Это и есть красота.