Что такое инфраструктурный слой (Infrastructure Layer) в чистой архитектуре?

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

Ответ

Инфраструктурный слой — это самый внешний слой в архитектуре приложения (например, в Clean Architecture или Hexagonal Architecture). Он содержит конкретные реализации абстракций, определённых во внутренних слоях (доменном и прикладном), и отвечает за взаимодействие с внешним миром.

Что находится в инфраструктурном слое:

  • Реализации репозиториев: Доступ к данным через конкретные технологии (MySQL через JDBC, MongoDB, REST API).
  • Внешние сервисы: Клиенты для email-рассылки, платежных шлюзов, message brokers (RabbitMQ, Kafka).
  • Фреймворки и драйверы: Веб-фреймворки (Spring MVC, JAX-RS), ORM (Hibernate), библиотеки для работы с файловой системой.
  • Конфигурация: Загрузка настроек из файлов, переменных окружения.

Ключевой принцип: Зависимости направлены вовнутрь. Инфраструктурный слой зависит от внутренних слоёв (домена и приложения), но не наоборот.

Пример на Java (Clean Architecture):

// 1. ДОМЕННЫЙ СЛОЙ (самый внутренний) - определяет абстракцию
package com.example.domain;
public interface UserRepository {
    User findById(UserId id);
    void save(User user);
}

// 2. ИНФРАСТРУКТУРНЫЙ СЛОЙ (самый внешний) - предоставляет реализацию
package com.example.infrastructure.persistence.jpa;
import com.example.domain.*;
import javax.persistence.EntityManager;

public class JpaUserRepository implements UserRepository {
    private final EntityManager em;
    // Зависимость на EntityManager (деталь инфраструктуры)
    public JpaUserRepository(EntityManager em) { this.em = em; }

    @Override
    public User findById(UserId id) {
        UserJpaEntity jpaEntity = em.find(UserJpaEntity.class, id.getValue());
        return jpaEntity != null ? jpaEntity.toDomain() : null;
    }

    @Override
    public void save(User user) {
        UserJpaEntity jpaEntity = UserJpaEntity.fromDomain(user);
        em.merge(jpaEntity); // Используем конкретный JPA API
    }
}

Таким образом, бизнес-логика (домен) ничего не знает о том, как именно хранятся данные — в MySQL, PostgreSQL или в файле. При необходимости можно заменить JpaUserRepository на InMemoryUserRepository для тестов или на MongoUserRepository без изменения кода домена.