Модульная архитектура в мобильной разработке: что это, как работает и когда нужна

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

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

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

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

Давайте разберем, как выглядит проект, который построен на «пазлах».

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

Заменим понятие пазл на такую структурную единицу как фреймворк. Каждый отдельный реализуемый функционал будет представлять собой совокупность кода для решения задачи и интегрироваться в проект как фреймворк.

Корневой проект, в котором размещены зависимости других проектов/фреймворков

В примере, который приведен выше, ModularApp — это корневой проект, а CoreModule, NavigationModule, SererApiModule и Onboarding — это модули или частицы, из которых состоит наш продукт.

В отличии от Onboarding модуля, первые три модуля всегда используются в наших проектах:

  • NavigationModule — отвечает за навигацию внутри наших проектов и позволяет получить доступ к любому стеку и флоу.
  • CoreModule — инициируется на старте проекта, в нем хранятся все стили и наборы представлений, которые будут использоваться.
  • ServerApiModule — модуль для работы с RestAPI.

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

Как распределять обязанности в проекте

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

Работу следует строить следующим образом:

  • Разработчик, который реализовывает модуль, должен быть владельцем репозитория;
  • Разработчики, которые снова и снова используют (reuse) модуль в своих проектах, могут лишь создавать свои ветки и работать с модулем отдельно от мастера.

Удобство в том, что всегда есть человек, который может провести код ревью, ведь он ведает про ценность, которую приносит этот код.

Как создать модуль

Пять простых шагов:

1. Необходимо создать проект с темплейта framework.

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

3. Приступить к разработке кода.

4. Для оценки и тестирования нашего кода понадобиться создать тестовый проект, в который мы добавим наш framework и доведем его до желаемого уровня.

5. После того, как мы заполнили кодом наши модули, необходимо описать весь функционал в нашем read.me файле.

На заметку

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

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

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

Интеграция нашего модуля в проект может проходить посредством стандартного набора: Swift Package Manager, Manual framework, carthage, cocoapods. При выборе провайдера необходимо учитывать некоторые факторы, а именно:

  • Carthage и Cocoapods — для публичного кода;
  • Manual framework и SPM позволяют использовать внутренний код;
  • Swift Package Manager не работает с объектами @IBDesignable, @IBInspectable.

Почему модули

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

Эти факторы привели нас к модулям, появилась стандартизация кода, привычка писать и читать код правильно. Швы выносились в отдельные модули и решались проблемы с функциональными задачами изолированно.

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

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

Есть ли минусы

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

Read the docs! Разработчик в команде не должен отвлекать разработчика модуля. Модуль считается мертвым, если нет документов.

Постоянная актуализация. Также необходимо поддерживать модули в актуальном состоянии как в основном проекте, так и в репозитории модулей. Поскольку каждый модуль представляет собой отдельный фреймворк, вам необходимо определить путь интеграции для SPM / CocoaPods / .framework.

Наш опыт

Мы в TRIARE разработали более 10 используемых модулей, которые активно развиваются. Есть 6 активных приложений, в основе которых лежат модули. Преимущества очевидны:

  • Увеличена скорость инициализации проектов и разработки;
  • Разработчики передают знания посредством описания кода модуля и документации;
  • Построен новый модуль навигации, который покрывает потребности и недостатки Router;
  • Облегчилась интеграция тестов, внедрение TDD;
  • Разрабатываемый код всегда актуален благодаря повторному использованию модулей;
  • Разработчикам стало легче переключаться между проектами и задачами, что привело к уменьшению bus factor.

Вместо вывода

Когда я только начинал изучать модули, все казалось слишком сложным. Теперь я могу сказать, что это не так. Я хочу, чтобы моя команда писала код легко. Никаких сложных архитектур, развертывание которых занимает 5-6 часов. Никаких проектов с устаревшим кодом, на обслуживание которых требуется 8 часов в день.

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

👍НравитсяПонравилось1
В избранноеВ избранном2
LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Нахлынули воспоминания про модули.Самое лучшее что я когда то пробовал это Modula-2.Вот где была красота!

Все циклично, старые подходы находят интерпретацию в новых системах)

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

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

Модули хороши там, где есть большая модульная платформа и жирное комьюнити, которое эти модули клепает. Хотя и есть немалые шансы сгородить монстра, но по современным меркам это вменяемая цена.

Но всё равно придёт время писать костыли. И вот тут уже вопрос к платформе, насколько она вообще заточена под костылинг. И совсем уж мечта всех мечт — чтобы были тулзы, которые проверят эти костыли при переходе на следующие версии. Потому что именно это ахиллесова пята модульных конструкций — приходится заново перекостыливать. Хорошо, когда знаешь, что делает костыль и зачем, когда это написано прямо в комментах костылю, и в доках проекта что там-то есть костыли.

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

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

Модули — это не панацея, если их правильно применять и не заигрываться, то они служат хорошим инструментом. Но, если пытаться их во всех местах возможных применять, то будет проблема с поддержкой и код будет обвешен костылями.

Модульная архитектура хороша там где надо разрабатывать много однотипного дерьма. Но вот ценник на изменения при смене какой-то платформы, например какую-то часть используемого кода забросили авторы и она стала угрозой безопасности — оказывается зачастую непомерным. Потому что оказывается, что менять надо всё. А модуля-то костыленные. И костыли даже при хорошей документированности переносить сложно, а делаются-то они как правило срочно-быстро, «на-вчера».

Так что в целом от модульной архитектуры следует ждать стабильности на протяжение 2 лет жизни, а вот дальше проблемы превращаются в снежный ком, и то что делалось командой, оказывается тяжело изменить одному человеку. А хрен же вы выделите команду по бюджету. И даже одного человека из прошлой команды. Скорее всего отдадут новому персонажу. Чем завалят и проект, и выгорание человеку обеспечат. Ничто так не выжигает, как чужой плохо документированный говнокод, который считается рабочим «да тут чуть-чуть поправить», но по факту он может даже не компилиться, ибо конфиги сборки потеряны и похерены.

А вот монолиты показывают удивительную стабильность и сравнительную лёгкость развития и изменения. Потому что они нифига не монолиты, просто их кубиками являются стандартные части фреймворков. И чтобы заменить какую-то часть, не нужно учить 100500 тулзов и кубиков, из которых собран каждый компонентик, притом с зависимостью от конкретной версии, и всё это на костылях.

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

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

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

Подписаться на комментарии