Найти тему
IW GROUP

Модуляризация iOS приложений

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

Добавьте описание
Добавьте описание

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

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

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

И здесь мы вспомним о модуляризации. Модуль – это отдельная независимая функционально законченная часть или фрагмент приложения.

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

Теперь давайте же рассмотрим сами виды модулей и их иерархическую структуру.

Добавьте описание
Добавьте описание

Иерархически, модули можно разделить на 3 уровня:

Core Modules - содержат удобные расширения, фасады для работы с системными функциями (например, LAConext), различные переиспользуемые UIKit компоненты и т.п.

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

Feature Modules - независимые инкапсулируемые части программы, содержащие полную или частичную функциональность какой-то бизнес задачи или фичи.

Например, в отдельный модуль можно вынести сервис авторизации или регистрации.

App - основное приложение, связывающее все модули и реализующее роутинг между ними.

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

  • Независимость - модули должны иметь возможность инкапсулировать в себе часть отдельной функциональности и работать независимо от других модулей;
  • Ответственность - модули должны быть ответственны и реализовывать только возложенный на них функционал;
  • Переиспользуемость - модули должны иметь возможность быть использованы повторно (в других проектах). Это требование является следствием двух предыдущих, но не является обязательным;
  • Инкапсулированность - модули должны скрывать частную реализацию той или иной функциональности, предоставляя публичный доступ только к нужным методам и свойствам.

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

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

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

- файл спецификации *.podspec - обязательно;

- файлы README и LICENSE - опционально;

- исходные файлы в виде *.framework, *.xcframework или набора *.swift и *.xib файлов, или любых других - обязательно.

Метод размещения модуля. Основные 2 способа, которые используем мы

при размещении модулей в проекте:

- в виде *.xcodeproj непосредственно в проекте;

- в виде отдельной зависимости, подключенной через менеджер зависимостей (мы используем cocoapods).

Для подключения модуля мы используем менеджер зависимостей cocoapods. Такой способ дает нам несколько преимуществ, которые рассмотрим далее.

Поставка модуля в виде pod-зависимости требует донастройки дополнительных компонентов:

  1. Модуль необходимо размещать в отдельном git-репозитории, который обычно создается в приватном пространстве
  2. Модуль необходимо расширить добавлением файла спецификации *.podspec

*.podspec – это файл спецификации, описывающий pod (модуль). Содержит в себе информацию о том, откуда должны быть извлечены исходные данные, общее описание модуля, параметры сборки и общие метаданные.

Наглядный пример синтаксиса podspec-файла:

Добавьте описание
Добавьте описание

s.name - имя модуля;

s.version - версия модуля;

s.summary и s.homepage - доп. информация (опционально);

s.author и s.license - информация о разработчике и лицензия (желательно);

s.platform - платформа для использования;

s.source - ссылка на репозиторий, откуда будет загружаться модуль;

s.ios.deployment_target - мин. версия платформы, которую поддерживает модуль (опционально);

s.ios.vendored_frameworks - имя фреймворка, который поставляется в модуле;

spec.source_files - путь на файлы, которые поставляются в модуле;

spec.dependency - имя дополнительной зависимости, необходимой для работы модуля (опционально).

Например, spec.dependency ‘Alamofire’, ‘4.9.3’ определяет, что для работы модуля AuthorizationService необходимо дополнительно установить библиотеку Alamofire версии 4.9.3.

Разместив модуль в git-репозитории и настроив для него файл спецификации, мы можем подключить его в наш проект через менеджер зависимостей cocoapods:

pod AuthorizationService, :git => 'https://gitlab/authorizationservice.git'

Cocoapods - мощный инструмент, позволяющий достаточно гибко поставлять модули в проект. На практике, часто приходится иметь возможность управлять версиями функциональностей, производить upgrade/degrade того или иного модуля, хранить несколько версий одного и того же модуля для различных проектов, и cocoapods позволяет легко этим управлять.

pod AuthorizationService, :git => 'https://gitlab/authorizationservice.git', :tag => ‘1.2.1’ - загрузка определенной версии модуля по tag

pod AuthorizationService, :git => 'https://gitlab/authorizationservice.git', :branch => ‘dev’ - загрузка определенной версии модуля из конкретного branch

pod AuthorizationService, :git => 'https://gitlab/ametov/authorizationservice.git', :commit => ‘45ae420wf’ - загрузка определенной версии модуля по hash commit

Для регулирования версии достаточно выполнить загрузку модуля посредством команды pod install.

Пришло время подвести итоги. Мы пришли к выводу, что модуляризация привносит в проект ряд технических и организационных преимуществ, а именно:

  1. Масштабируемость - разработка каждого модуля ведется отдельно, имеется возможность расширять команды разработки, которые работают над отдельными модулями и не пересекаются;
  2. Экономия ресурсов - модули реализуются с учетом возможности переиспользоваться или дорабатываться под конкретные нужды;
  3. Связность кода, а точнее ее уменьшение. Модули не пересекаются друг с другом, уменьшение связей и соблюдение code style влечет за собой упрощение разработки и уменьшение входного порога для разработчиков.

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

А вы что думаете о модуляризации?