Привет! На связи команда Joy Dev. Представим ситуацию, вы работаете над проектом, дела идут хорошо, проект растет, и в какой‑то момент вас в команде становится все больше и больше! Проект вырастает, и становится много модулей и фич, но появились проблемы:

  • из‑за большого объема модулей все сложнее ориентироваться в проекте (не говоря уже о том, чтобы погрузиться в него с нуля);

  • фичи не разделены, а это значит, что перенести или заменить какой‑либо модуль становится долгим и болезненным делом;

  • проект собирается мучительно долго;

  • от мысли о конфликтах в файле проекта *.pbxcodeproj бросает в дрожь.

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

  1. Development Pods

  2. Сабмодуль на отдельном репозитории

  3. Подпроект

Почему мы решили прибегнуть к модульности

На одном из наших проектов в один момент стало огромное количество кода:

  • по верстке UI компонентов, который переиспользовался по всему проекту, но редко модифицировался;

  • утилиты и расширения к стандартным сущностям;

  • слой по работе с сетью и локальному хранению данных;

  • существенный объем legacy кода, который подлежал рефакторингу. Однако было трудно организовать работу нескольких разработчиков над кодом из‑за постоянных конфликтов.

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

Лучше всего помогает решить эти проблемы именно модульность проекта.

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

Development Pods

Development Pods или по‑простому «девподы» — это полезный и удобный инструмент. Девподы — модули с символическими ссылками, при изменении которых изменяются оригинальные файлы.

Как создать девпод в проекте?

1. Создаем папку модуля.

Pod::Spec.new do |s|
   s.name = ‘MyModule’
   s.version = ‘1.0’
   s.summary = 'My Module Summary'
   s.homepage = ‘Some link’
   s.author = { ‘name’ => ‘name@joy-dev.com’ }
   s.source = { :path => "." }
   s.platform = :iOS, ’13.0’
   s.swift_version = ‘5.0’
   s.source_files = ‘MyClasses/*’
end

3. Включаем наш новоиспеченный модуль в основной Podfile проекта.

pod "MyModule", :path => "./MyModulesFolder/MyModule"

4. Выполняем установку подов и в Pods проекте видим папку Development Pods.

5. Для использования модуля в основном проекте достаточно включить его в файл import MyModule.

Преимущества Dev Pods

  • для большой команды: при такой модульной структуре «толкания локтями» становится гораздо меньше, конфликты в файле проекта становятся редкостью, разрабатывать отдельные фичи можно независимо и безболезненно;

  • для оптимизации времени сборки: Xcode не будет пересобирать девпод, если в нем не вносилось никаких изменений;

  • для визуального разбиения кода на модули: больше не придется перекапывать 20 папок в поисках того самого экрана.

Недостатки Dev Pods

  • придется изменить файловую структуру проекта: все компоненты необходимо сложить в одну папку;

  • не поддерживают версионность;

  • необходимо менять модификаторы доступа у всех публичных сущностей методов extension на public.

Сабмодуль на отдельном репозитории

Удобное решение при затягивании отдельного независимого модуля или работы двух команд над проектом. Пара простых примеров, когда это полезно: модуль со всеми UI‑компонентами и стилями, которые используются в верстке (дизайн‑система) или модуль с сетевым слоем. Такой сабмодуль затягивается, как отдельный под по ссылке на репозиторий с указанием версии.

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

Имхо, самое лучшее в таком подходе — это возможность управлять версиями подов, накатывать новые изменения или откатываться до предыдущих.

Итого, если выносим отдельные файлы (набор UI‑компонентов)/модуль работы с API — это очень удобно.

Указываем в подфайле зависимость одним из способов:

  • source “https://github.com/nfme/JoyDevDesignSystem.git”

    pod 'JoyDevDesignSystem', '0.0.1'

  • pod “JoyDevDesignSystem”,:git => “https://github.com/name/JoyDevDesignSystem.git”,:tag => '0.0.1'

Плюсы Сабмодуля

  • не нужно беспокоиться о внешних зависимостях;

  • можно версионировать: удобно откатывать изменения до нужной версии.

    Если хотим вынести, к примеру, «Экран каталога товаров», то здесь проявляются минусы такого подхода.

  • более сложное вынесение модуля из‑за необходимости создавать гит‑проект;

  • усложняется процесс‑ревью: придется ревьюить по модулям (например, при создании нового экрана, отдельно ревью UI, отдельно моделей и сервисов);

  • работа с несколькими репозиториями в рамках одной задачи;

  • нет оптимизации по времени — файлы будут билдиться вместе со всем проектом.

Подпроект

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

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

Такой подход к модульности отлично сочетается с использованием утилит для генерации проектов — например, XcodeGen. Если затянуть себе такую утилиту, то можно просто и быстро генерировать подпроекты из конфиг‑файлов (yml, например) и вовсе забыть о конфликтах в файле проекта.

Как создать подпроект

  1. Создаем новый проект.

  1. Помещаем его в папку проекта.

  1. Получаем следующую структуру.

  1. Добавляем зависимость в основной модуль.

Преимущества подпроектов

  • pbxproj‑файл разбивается на несколько, т. е. конфликтов в файле проекта сразу меньше, соответственно, разные команды могут одновременно работать над разными подпроектами;

  • модули реализованы наглядно;

  • автоматически определяется принадлежность файлов;

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

Недостатки подпроектов

  • нужно полностью изменить структуру проекта;

  • необходимо менять модификаторы доступа у всех сущностей методов extension на public.

Что выбирать

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

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

Комментарии (0)