Структура системы

Слоистая архитектура, гексагональная архитектура, микроядро, клиент-сервер

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

Все четыре паттерна показаны на одной задаче - регистрации по email, - поэтому разница видна напрямую: те же правила, разное устройство вокруг них.

  • Направление зависимостей: в слоистой архитектуре вызовы идут сверху вниз, до хранилища. В гексагональной архитектуре и микроядре всё зависит от ядра, а ядро - ни от чего снаружи.
  • Граница процесса: слоистая, гексагональная архитектура и микроядро могут жить в одном процессе. В клиент-серверной архитектуре между частями сеть, и ответ может потеряться по дороге.

  • Слоистая архитектура - простой старт для обычного приложения: экран, правила, хранение и база стопкой, каждый слой зовёт только нижний.
  • Гексагональная архитектура - когда правила должны работать и тестироваться без базы и интерфейса, а хранилище или форму нужно заменять адаптером того же порта.
  • Микроядро - когда продукт растёт подключаемыми плагинами, а ядро остаётся тем же: редакторы, IDE, браузеры с расширениями.
  • Клиент-сервер - когда данные и правила должны быть общими для многих пользователей, а интерфейс работает у каждого на своём устройстве.

Стили сочетаются: сервер в клиент-серверной системе внутри может быть слоистым или гексагональным, а ядро микроядра - разделено на слои.

Слой (layer) - логическая часть кода: модуль или набор классов с одной ответственностью. Уровень (tier) - физическая часть: отдельный процесс или машина. Слои могут жить на одном уровне, а один слой не обязан совпадать с уровнем.

  • Вызов внутри процесса возвращает результат значением и не теряется - так общаются слои.
  • Сообщение по сети может потеряться, прийти поздно или дважды - поэтому в клиент-серверном примере запрос и ответ нарисованы отдельными стрелками, а повтор идёт с тем же ключом запроса.

  • По тому, что заменяемо: нижний слой (Layered), адаптер у порта (Hexagonal), плагин в слоте (Microkernel), клиент или сервер по общему протоколу (Client-Server).
  • По смыслу стрелки на схеме: в слоистой и клиент-серверной это вызов или сообщение по направлению движения, в гексагональной и микроядре - зависимость, которая всегда указывает на ядро.
  • По тому, что защищено от изменений: правила в ядре (Hexagonal, Microkernel) или верхние слои от деталей нижних (Layered).

Слоистая архитектура

Слоистая архитектура (Layered Architecture) делит приложение на горизонтальные слои, у каждого из которых одна техническая роль: показать данные пользователю, применить бизнес-правила, сохранить и прочитать данные. Слой обращается только к слою под ним, а нижние слои ничего не знают о верхних. Поэтому любой слой можно понять, протестировать и заменить, не разбираясь в остальных.

Гексагональная архитектура

Гексагональная архитектура (Hexagonal Architecture), её второе название - Порты и адаптеры (Ports and Adapters), ставит бизнес-правила в центр приложения и отделяет их от всего внешнего: интерфейса, базы данных, тестов. Ядро объявляет порты - интерфейсы, через которые с ним можно говорить и через которые оно само просит данные, - а снаружи к портам подключаются адаптеры. Все зависимости направлены внутрь, к ядру, поэтому интерфейс или хранилище можно заменить другим адаптером того же порта, не меняя ни строчки в правилах.

Архитектура микроядра

Архитектура микроядра (Microkernel Architecture), её также называют архитектурой плагинов (plug-in architecture), делит приложение на маленькое ядро с минимумом функций и подключаемые к нему плагины. Ядро знает, какие плагины установлены, и вызывает их через общий контракт, а каждая новая функция или правило продукта приходит отдельным плагином. Поэтому возможности продукта растут и настраиваются под конкретного клиента подключением и отключением плагинов, а не правкой ядра - пока новый плагин укладывается в контракт ядра.

Клиент-серверная архитектура

Клиент-серверная архитектура (Client-Server Architecture) делит систему на две роли, которые работают в разных процессах и обычно на разных машинах: клиенты отправляют запросы, а сервер их обрабатывает и отвечает. Данные и правила, которым можно доверять, живут на сервере, и он - единственный источник истины сразу для всех клиентов. Клиент бывает тонким или толстым, но последнее слово в том, чему можно доверять, всегда за сервером. Между ними лежит сеть, поэтому каждое сообщение сериализуется, идёт с задержкой и может потеряться.