Многомодульность

May 26, 2020 · View on GitHub

Главная

Многомодульность

Все приложения, которые мы проектируем с нуля, имеют многомодульную структуру.

Зачем?

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

  • Нарушения архитектурных принципов невозможны. Каждый модуль имеет определённую зону ответственности и изолирован от соседних;
  • Прозрачный dependency-management обеспечен. Все горизонтальные связи между модулями и вертикальные зависимости жёстко регламентированы и прозрачны;
  • Скорость сборки проекта оптимизирована. При сборке правильно спроектированного многомодульного проекта эффективно используются вычислительные возможности железа, так как все независимые модули могут собираться параллельно на разных ядрах CPU. Инкрементальная сборка также позволяет сэкономить время, за счёт переиспользования артефактов, в которых с момента последней сборки не произошло никаких изменений;
  • Переиспользование кода упрощено. Модули легко шарятся между проектами и относительно безболезненно изымаются из проекта.

Как?

Типы слоёв.

Каждый модуль принадлежит к тому или иному слою. У каждого слоя есть своя чётко определённая роль.

  • Сервисный - этого слоя не найти в традиционной диаграмме Clean Architecture. Его роль - инфраструктурная;
  • Функциональный - слой, отвечающий за отображение пользовательского интерфейса и обработку пользовательского ввода;
  • Логический - слой, консолидирующий в себе всю бизнес-логику приложения;
  • Базовый - слой для абстрактного и переиспользуемого кода.

Типы модулей.

Основные типы модулей по слоям:

Сервисный слой.

  • App - не содержит никакого кода и ресурсов. Существует в проекте в единственном экземпляре. Отвечает за производство файла сборки (.apk или .aab). Именование: 'app';
    • Имеются прямые или транзитивные зависимости на все модули проекта.

Функциональный слой.

  • Feature - отвечают за отображение UI в рамках одной полноценной единицы функциональности ("Главный экран", "Поиск", "Корзина"). Могут содержать реализацию нескольких экранов и набор необходимых ресурсов для них. Навигация между двумя Activity, принадлежащими разным feature-модулями осуществляется посредством соответствующей реализации CrossFeatureRoute. Именование: 'f_feature_name';
    • Недопустимы зависимости на другие f-модули;
    • Допустимы зависимости на cf-модули;
    • Допустимы зависимости на i-модули;
    • Обязательна зависимость на bf-модуль;
  • Common-Feature - отвечают за отображение UI в рамках блока функциональности, как правило небольшого и не основанного на базе Activity, используемого более чем в одном feature-модуле (фрагмент с лентой постов, кастомный диалог выбора изображения из галереи). Именование: 'cf_feature_name';
    • Недопустимы зависимости на f-модули;
    • Нежелательны зависимости на другие cf-модули;
    • Допустимы зависимости на i-модули;
    • Обязательна зависимость на bf-модуль.

Логический слой.

  • Interactor - отвечают за реализацию бизнес-логики в рамках, чаще всего очерченных предметной областью приложения (пользователи, поиск, комментарии, оплата). Именование: 'i_name';
    • Недопустимы зависимости на f-модули;
    • Недопустимы зависимости на cf-модули;
    • Недопустма зависимость на bf-модуль;
    • Допустимы зависимости на другие i-модули;
    • Допустимы зависимости на i-domain-модуль;
    • Обязательна зависимость на base-модуль;
  • Interactor-Domain - является аналогом domain-модуля, но отвечает за маппинг сырых моделей слоя данных в модели, используемые на UI-слое. Его существование призвано снизить связность i-модулей между собой, так как часто приходилось устанавливать зависимость между i-модулями только лишь из-за переиспользования в них маппинг-моделей. Существует в проекте в единственном экземпляре. Именование: 'i_domain';
    • Недопустимы зависимости на другие модули.

Базовый слой.

  • Base-Feature - содержит весь базовый код UI слоя, а также отвечает за инициализацию графа зависимостей приложения. Существует в проекте в единственном экземпляре. Содержит Application-класс приложения и все CrossFeatureRoute для навигации между экранами из различных feature-модулей. Именование: 'base_feature';
    • Недопустимы зависимости на f-модули;
    • Недопустимы зависимости на cf-модули;
    • Недопустимы зависимости на i-модули;
    • Обязательна зависимость на base-модуль;
  • Base - содержит только базовый код, который может потребоваться и при реализации UI слоя, и при реализации слоя бизнес-логики (аналитика, KTX, валидаторы, кастомные ошибки и т.д.). Существует в проекте в единственном экземпляре. Именование: 'base';
    • Недопустимы зависимости на все вышеперечисленные типы модулей;
    • Обязательна зависимость на domain-модуль;
  • Domain - содержит только простые data-модели предметной области приложения. Существует в проекте в единственном экземпляре. Именование: 'domain';
    • Недопустимы зависимости на другие модули.