Шестиугольная архитектура заменяет многоуровневый стиль, и вот почему

Гексагональная архитектура — это архитектурный шаблон для разработки программных приложений. Его популярность возросла в последние годы, поскольку он является альтернативой традиционной многоуровневой архитектуре. В этой статье я объясню, почему гексагональная архитектура заменяет многоуровневую архитектуру.

В чем проблема многоуровневой архитектуры?

В этом архитектурном шаблоне применяется принцип SoC (разделение задач) для разложения наших компонентов на уровни, каждый из которых несет свою ответственность. Обычно выделяют 3 слоя:

  1. Слой представления, содержащий пользовательский интерфейс.
  2. Бизнес-уровень или уровень домена, содержащий бизнес-логику.
  3. Уровень сохраняемости, отвечающий за операции с базой данных.

При применении этого архитектурного паттерна мы сталкиваемся с зависимостью между слоями, то есть каждый слой зависит от слоя, находящегося непосредственно под ним.

Эта модель не показывает, что мы можем взаимодействовать более чем с одной базой данных или вообще не взаимодействовать ни с одной базой данных. Кроме того, уровень представления не учитывает, что у пользователя может быть более одного способа взаимодействия с нашим приложением.

Как шестиугольная архитектура преодолевает недостатки многоуровневой архитектуры?

Эта модель помещает всю бизнес-логику в ядро ​​приложения, абстрагируя любые внешние зависимости. Эта изоляция значительно упрощает тестирование и поддержку логики.

Вместо уровня представления приложение теперь имеет один или несколько входных адаптеров, обрабатывающих запросы пользователей. Точно так же вместо уровня сохраняемости теперь у нас есть один или несколько выходных адаптеров, которые вызывают внешние приложения или службы, такие как хранилище файлов в Amazon S3, служба электронной почты, такая как SendGrid, или, что более типично, база данных.

Бизнес-ядро имеет один или несколько портов. Порт определяет набор операций, позволяющих ядру взаимодействовать с адаптерами и, следовательно, с тем, что находится за пределами приложения. Так же, как у нас есть два типа адаптеров, входной и выходной, есть входной порт и выходной порт. Входные порты — это API-интерфейсы, предоставляемые ядром для доступа к внешним приложениям, а выходные порты — это интерфейсы, которые позволяют ядру использовать внешние службы.

Входной адаптер обрабатывает запрос из внешнего мира, вызывая входной порт. Примером этого может быть контроллер Spring, реализующий REST API или сервер gRPC.

Выходной адаптер реализует выходной порт, который обрабатывает запросы от бизнес-ядра, вызывая внешнее приложение или службу. Некоторыми примерами являются класс DAO (объект доступа к данным), выполняющий операции с базой данных, или компонент Spring, использующий службу электронной почты.

Как мы можем решить этот архитектурный стиль в Spring?

До сих пор мы видели концепции, связанные с гексагональной архитектурой. Теперь давайте применим теорию на практике и создадим приложение Spring с помощью Kotlin.

Для начала лично мне нравится делить проект на три основных пакета:

  • Пакет «core», содержащий компоненты, относящиеся к основному бизнесу.
  • Пакет «ports», содержащий компоненты ввода и вывода, которые связывают ядро ​​бизнеса с внешним миром.
  • Пакет «config» для всех конфигураций, необходимых для запуска приложения и управления его внутренним поведением.

Создание ядра

Вот наша сущность Article. Обратите внимание, что он написан на простом Kotlin (или Java), но прекрасно представляет бизнес-объект.

Вот интерфейс ArticleRepository, который позволяет бизнес-ядру взаимодействовать с внешними сервисами.

Вот интерфейс ArticleService, который позволяет внешним приложениям взаимодействовать с бизнес-ядром.

Внутри usecasepackageкласс ArticleServiceImpl расширяет ArticleService и содержит фактическую бизнес-логику.

Выходной порт для адаптера базы данных

Пакет ports/output/jpa содержит компоненты для сохранения данных в базе данных.

Вот класс ArticleJpa, основанный на основной сущности.

Вот класс ArticleJpaRepository, который расширяет JpaRepository из библиотеки Spring JPA.

Здесь класс ArticleDao расширяет класс ArticleRepository, позволяя бизнес-ядру извлекать и сохранять данные.

Входной порт для адаптера REST

Наконец, пакет ports/inputs/rs содержит контроллеры Rest, предоставляющие конечные точки для использования внешними приложениями.

Почему важна архитектура?

При разработке программного обеспечения существует набор основных требований, известных как требования к качеству обслуживания. Эти требования определяют некоторые компромиссы, на которые мы должны обратить внимание в процессе создания качественного программного обеспечения, такие как масштабируемость, надежность, ремонтопригодность, тестируемость и возможность развертывания.

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

Спасибо за прочтение. Я надеюсь, что это было полезно!

Код примера доступен на GitHub.