Что такое шестигранная архитектура (Hexagonal Architecture) и каковы её принципы?

«Что такое шестигранная архитектура (Hexagonal Architecture) и каковы её принципы?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Шестигранная архитектура (Ports & Adapters) — это паттерн, который изолирует бизнес-логику (ядро) от внешних зависимостей (UI, БД, внешние сервисы) через абстракции (порты) и их реализации (адаптеры).

Ключевые компоненты:

  1. Ядро (Domain): Содержит бизнес-логику и сущности. Не зависит от внешнего мира.
  2. Порты (Ports): Интерфейсы, которые определяют, как ядро взаимодействует с внешним миром.
    • Входные порты (Driving Ports): Для получения команд/запросов (например, UserService).
    • Выходные порты (Driven Ports): Для доступа к данным или внешним сервисам (например, UserRepository).
  3. Адаптеры (Adapters): Реализации портов, которые переводят запросы из внешнего мира в вызовы ядра и наоборот.

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

// ЯДРО (не зависит от фреймворков)
// Выходной порт (интерфейс, который определяет ядро)
public interface UserRepositoryPort {
    User findById(Long id);
}

// Входной порт (сервис, реализующий бизнес-логику)
public class UserService {
    private final UserRepositoryPort repository;
    public UserService(UserRepositoryPort repository) {
        this.repository = repository; // Dependency Injection
    }
    public User getUser(Long id) {
        // Бизнес-логика (например, валидация)
        return repository.findById(id);
    }
}

// АДАПТЕР ВНЕШНЕГО МИРА (зависит от фреймворка, например, Spring Data JPA)
@Component
public class JpaUserRepositoryAdapter implements UserRepositoryPort {
    @Override
    public User findById(Long id) {
        // Реализация с использованием JPA (Spring Data)
        return jpaRepository.findById(id).orElse(null);
    }
}

Преимущества:

  • Тестируемость: Ядро можно тестировать в изоляции с помощью мок-адаптеров.
  • Гибкость: Замена базы данных или UI требует изменения только адаптера, а не бизнес-логики.
  • Сохранность бизнес-правил: Ядро защищено от изменений во внешних фреймворках.

Недостатки:

  • Сложность: Увеличивает количество слоев и boilerplate-кода.
  • Избыточность: Может быть неподходящей для простых CRUD-приложений.