Что означает принцип чистоты слоёв (Layer Purity) в архитектуре?

«Что означает принцип чистоты слоёв (Layer Purity) в архитектуре?» — вопрос из категории Архитектура, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Чистота слоёв — это архитектурный принцип, требующий, чтобы каждый слой в многослойной (N-слойной) архитектуре приложения имел строго определённую ответственность и не «протекал» в соседние слои, нарушая границы абстракции.

Суть принципа: Слой должен зависеть только от слоёв, находящихся ниже него (ближе к инфраструктуре), и не должен знать о деталях реализации слоёв выше него (ближе к пользователю).

Классическое нарушение (Антипаттерн):

// Presentation Layer (например, контроллер ASP.NET или код формы)
public class UserController : Controller
{
    public IActionResult GetUsers()
    {
        // НАРУШЕНИЕ: Presentation Layer напрямую работает с БД
        var connectionString = Configuration.GetConnectionString("Default");
        using (var connection = new SqlConnection(connectionString))
        {
            var users = connection.Query<User>("SELECT * FROM Users");
            return View(users);
        }
    }
}

Правильный подход с чистыми слоями:

// Presentation Layer (Controller) -> ЗАВИСИТ от Business Layer
public class UserController : Controller
{
    private readonly IUserService _userService; // Абстракция бизнес-уровня
    public UserController(IUserService userService) => _userService = userService;

    public async Task<IActionResult> GetUsers()
    {
        var users = await _userService.GetAllActiveUsersAsync(); // Делегирование
        return View(users);
    }
}

// Business Layer (Service) -> ЗАВИСИТ от Data Access Layer
public class UserService : IUserService
{
    private readonly IUserRepository _repository;
    public UserService(IUserRepository repository) => _repository = repository;

    public async Task<List<User>> GetAllActiveUsersAsync()
    {
        var allUsers = await _repository.GetAllAsync();
        // Бизнес-правило: фильтрация активных пользователей
        return allUsers.Where(u => u.IsActive).ToList();
    }
}

// Data Access Layer (Repository) -> Работает с БД или внешним API
public class UserRepository : IUserRepository
{
    private readonly AppDbContext _context;
    public UserRepository(AppDbContext context) => _context = context;

    public async Task<List<User>> GetAllAsync() => await _context.Users.ToListAsync();
}

Преимущества соблюдения чистоты слоёв:

  • Тестируемость: Каждый слой можно тестировать изолированно, подменяя зависимости.
  • Поддерживаемость: Изменения в одном слое (например, замена БД) минимально затрагивают другие.
  • Чёткое разделение ответственности: Упрощает понимание кода и onboarding новых разработчиков.
  • Гибкость: Позволяет относительно легко менять технологический стек отдельного слоя.