Что такое Application слой (уровень приложения) в архитектуре?

Ответ

Application слой (уровень приложений) — это слой в многослойной архитектуре (например, Clean Architecture, Onion), который отвечает за координацию рабочих процессов приложения и реализацию сценариев использования (Use Cases). Он служит посредником между внешними интерфейсами (Presentation/UI) и доменной логикой (Domain Layer).

Ключевые обязанности:

  • Оркестрация: Координация вызовов к доменным объектам, репозиториям и внешним сервисам для выполнения конкретного сценария.
  • Транзакционность: Управление границами транзакций для операции.
  • Валидация входных данных: Проверка DTO (Data Transfer Objects) на корректность с точки зрения приложения.
  • Преобразование данных: Маппинг между доменными моделями и DTO для ввода/вывода.

Пример Application Service на C#:

public class PlaceOrderService // Application Service
{
    private readonly IOrderRepository _orderRepository;
    private readonly IInventoryClient _inventoryClient;

    public PlaceOrderService(IOrderRepository orderRepository, IInventoryClient inventoryClient)
    {
        _orderRepository = orderRepository;
        _inventoryClient = inventoryClient;
    }

    public async Task<OrderResultDto> Execute(PlaceOrderCommand command)
    {
        // 1. Валидация входных данных (Application concern)
        if (command.Items == null || !command.Items.Any())
            throw new InvalidRequestException("Order must contain items.");

        // 2. Координация доменной логики и инфраструктуры
        var productIds = command.Items.Select(i => i.ProductId).ToList();
        var areAvailable = await _inventoryClient.CheckAvailability(productIds);
        if (!areAvailable)
            throw new DomainException("Products are out of stock.");

        // 3. Создание и сохранение доменного агрегата (Domain concern)
        var order = new Order(command.CustomerId);
        foreach (var item in command.Items)
        {
            order.AddItem(item.ProductId, item.Quantity);
        }

        await _orderRepository.AddAsync(order);
        await _orderRepository.UnitOfWork.SaveChangesAsync(); // Управление транзакцией

        // 4. Возврат DTO (Application concern)
        return new OrderResultDto { OrderId = order.Id, Status = order.Status };
    }
}

Важно: Application слой не содержит сложной бизнес-логики (это Domain Layer) и инфраструктурных деталей (доступ к БД, вызов API — это Infrastructure Layer).

Ответ 18+ 🔞

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

Смотри, есть у тебя домен — это святое, ядро, где живут твои бизнес-правила, самые важные сущности. Их нельзя ничем засирать, никакими базами или апишками. А есть внешний мир — контроллеры, база, другие сервисы. Так вот, между ними нужно поставить надёжного буфера, который будет всем этим хозяйством рулить, но сам при этом в бизнес-логику лезть не будет. Это и есть Application слой, или, как его ещё обзывают, слой приложений.

Чем он, бедолага, занимается, пока ты кофе пьёшь:

  • Оркестрация, блядь. Он как дирижёр в оркестре: сам на скрипке не играет, но командует, когда доменным объектам вступать, когда репозиторию данные тащить, а когда внешнему сервису чекнуть наличие товара. Просто координирует процесс для конкретного сценария (Use Case).
  • Транзакционность. Он следит, чтобы операция либо полностью выполнилась, либо откатилась, как будто её и не было. Нельзя же половину заказа создать, а потом упасть с ошибкой — это пиздец пользователю.
  • Валидация входных данных. Не ту бизнес-валидацию, что «скидка не больше 100%» (это домен), а прикладную: «а команда-то вообще пришла?», «а список товаров не пустой?». Элементарные проверки, чтобы мусор в домен не тащить.
  • Преобразование данных. Он знает, как твой красивый доменный Order превратить в убогий OrderResultDto для фронта, и наоборот. Домену-то похуй на эти DTO, ему бы свои инварианты сохранить.

А вот чего он НЕ делает, ни под каким соусом:

  • Не содержит сложной бизнес-логики. Это не его епархия. Его дело — позвать нужный доменный метод в нужное время.
  • Не лезет в инфраструктурные детали. Как именно данные из БД достаются или как дергается внешнее АПИ — его не ебёт. Он работает через абстракции (интерфейсы).

Смотри, как это выглядит в коде, на примере сервиса оформления заказа:

public class PlaceOrderService // Это он, Application Service
{
    // Зависимости через интерфейсы. Инфраструктура? Похуй, главное — контракт.
    private readonly IOrderRepository _orderRepository;
    private readonly IInventoryClient _inventoryClient;

    public PlaceOrderService(IOrderRepository orderRepository, IInventoryClient inventoryClient)
    {
        _orderRepository = orderRepository;
        _inventoryClient = inventoryClient;
    }

    public async Task<OrderResultDto> Execute(PlaceOrderCommand command)
    {
        // 1. Прикладная валидация: "Чувак, ты мне вообще что-то прислал?"
        if (command.Items == null || !command.Items.Any())
            throw new InvalidRequestException("Order must contain items.");

        // 2. Оркестрация: сначала дергаем внешний сервис проверить наличие
        var productIds = command.Items.Select(i => i.ProductId).ToList();
        var areAvailable = await _inventoryClient.CheckAvailability(productIds);
        if (!areAvailable)
            throw new DomainException("Products are out of stock."); // Доменную исключил, но кинул её АППЛИКЕЙШН

        // 3. Работа с доменом: создаём агрегат, используем его логику
        var order = new Order(command.CustomerId);
        foreach (var item in command.Items)
        {
            order.AddItem(item.ProductId, item.Quantity); // Вот тут доменный метод!
        }

        // 4. Сохраняем через абстракцию и фиксируем транзакцию
        await _orderRepository.AddAsync(order);
        await _orderRepository.UnitOfWork.SaveChangesAsync();

        // 5. Возвращаем результат, понятный внешнему миру (DTO)
        return new OrderResultDto { OrderId = order.Id, Status = order.Status };
    }
}

Короче, Application слой — это твой надёжный управляющий. Он не умничает с бизнес-правилами (это удел домена) и не парится, как там база данных устроена (это инфраструктура). Его задача — грамотно, в правильном порядке, позвать нужных ребят на сцену, чтобы сценарий использования отработал чётко, как швейцарские часы. А если начнёт в чужое лезть — получится та самая каша, где всё связано со всем, и потом любое изменение стоит, как чугунный мост.