Почему CatalogRepository вынесен в слой Infrastructure, а не в Application?

«Почему CatalogRepository вынесен в слой Infrastructure, а не в Application?» — вопрос из категории Архитектура, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

CatalogRepository размещается в слое Infrastructure, потому что он содержит конкретную реализацию доступа к данным (например, использует EF Core, Dapper или внешний API). Это соответствует принципу Dependency Inversion (DIP) и принципам чистой архитектуры или Onion Architecture.

Почему это важно:

  1. Разделение ответственности: Слой Application содержит бизнес-логику и абстракции (интерфейсы репозиториев), а Infrastructure — их конкретные реализации.
  2. Тестируемость: Бизнес-логику в Application можно легко протестировать с помощью mock-объектов, подменяя реальный репозиторий.
  3. Гибкость: Технологию доступа к данным (например, смена ORM или переход на gRPC) можно изменить, не затрагивая ядро приложения.

Пример структуры:

// Application Layer (абстракция)
namespace MyApp.Application.Interfaces;
public interface ICatalogRepository
{
    Task<Product> GetByIdAsync(int id, CancellationToken cancellationToken);
}

// Infrastructure Layer (реализация)
namespace MyApp.Infrastructure.Persistence.Repositories;
public class CatalogRepository : ICatalogRepository
{
    private readonly ApplicationDbContext _context;
    public CatalogRepository(ApplicationDbContext context) => _context = context;

    public async Task<Product> GetByIdAsync(int id, CancellationToken cancellationToken)
    {
        return await _context.Products
            .AsNoTracking()
            .FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
    }
}

Таким образом, зависимость направлена от деталей (Infrastructure) к абстракциям (Application), что делает архитектуру устойчивой к изменениям.