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

Многие разработчики знакомы с понятиями слоистой архитектуры.

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

Инфраструктурный слой, например, общается с базой данных, доменный слой отвечает за бизнес-правила.

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

Горизонтальное деление

Слоистая архитектура делит приложение горизонтально.

Горизонтальное деление по слоям

Вертикальное деление

Для достижения хорошей модульности можно делить приложение вертикальными срезами.

Если упростить, то один вертикальный срез = один модуль. Одна “фича” в системе или группа фич.

Здесь и далее под “модульностью” и “делением по модулям” я подразумеваю вертикальное деление.

Отличие от горизонтального деления в том, что в вертикальный срез входит весь код, относящийся к одной функциональности.

Вертикальные срезы по функциональности

Пример

Допустим в приложении есть функциональность “регистрация пользователей”.

В вертикальный срез будет входить всё что обеспечивает эту функциональность:

  • файлы представлений
  • вёрстка
  • JS
  • тесты
  • модели
  • таблицы
  • миграции
  • контроллеры
  • сервисы
  • валидаторы и так далее.

Всё это будет сгруппировано в один модуль.

Пример деления

Рассмотрим как выглядит деление на примере простого приложения доставки.

В приложении есть функциональность отправки СМС, интерфейс для модераторов сервиса и интерфейс позволяющий клиентам заказать доставку.

Деление по слоям, горизонтальное

Деление приложения доставки по слоям

Деление по модулям, вертикальное

Деление приложения доставки по модулям

Как происходит деление

Как осуществляется деление кода?

Группировка по папкам

Во-первых, мы группируем код по папкам.

В слоистой архитектуре на верхнем уровне будут папки соответствующие слою.

В вертикальном делении по модулям, на верхнем уровне будут папки модулей.

Архитектурные границы

Во-вторых, для обеспечения деления мы проводим архитектурные границы.

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

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

Сочетание вертикального и горизонтального деления

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

Ну какой там “домен” когда у тебя три-четыре сущности в одном модуле?

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

Плюсы вертикального деления

Мы получаем изоляцию кода “по фичам”, тем самым отвязываем в коде одну часть бизнес-логики от другой.

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

Если один модуль не завязан на другой, то внося изменения в один модуль мы не сломаем остальные.

Оперировать в рамках 5 таблиц, моделей и пары контроллеров будет легче чем с 100 таблиц, моделей и десятками контроллеров.

Плюсы вертикального деления:

  • Увеличивается скорость разработки
  • Упрощается поддержка
  • Повышается надёжность

Минусы вертикального деления

Деление по модулям (вертикальное) требует дисциплины, хорошего понимания процессов разработки и в целом большого опыта.

Если в команде нет разработчиков с достаточным опытом и знанием архитектурных принципов, то правильно поделить на модули с первого раза не получится, поэтому есть риск что сложится мнение что “этот подход не работает”.

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

Минусы вертикального деления:

  • Сложно затащить, есть риск не справиться
  • Нужно обучать разработчиков работе с модулями
  • Придётся решать архитектурные проблемы

Борьба со сложностью

По моему опыту деление на модули пожалуй самое эффективное и универсальное средство против сложности.

Рядом с ним все остальные, например разбивка по слоям, дают сильно меньший эффект.

При этом деление на модули не противоречит и отлично сочетается с любой другой архитектурной практикой.

Например, можно разделить приложение на модули а в модулях побить по слоям.

Ссылки

1. Компания iSpring. Доклад Юлии Николаевой (Insolita) про модульный монолит: youtube

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

2. Доклад Валентина Удальцова про структурирование кода в компании HappyInc: youtube

P.S. Взаимодействие модулей

Поделить-то поделили, а как модулям общаться друг с другом?

Рассматриваем в статье “4 способа взаимодействия модулей”.