Что даёт модульный каркас: скорость сборки и предсказуемость
Модульный каркас на схеме VIPER разбивает приложение на независимые модули, где экран — это набор изолированных слоёв: представление, логика, работа с данными. Слои связаны только через контракты, поэтому правка в одном экране не задевает соседние, а сборка пересобирает один модуль вместо всего проекта — время сборки проекта перестаёт расти вместе с числом экранов.
Однотипные слои не пишем руками: генератор модулей по шаблону создаёт заготовки с едиными точками входа и уже связанными зависимостями, разработчик сразу пишет логику. Структура остаётся одинаковой во всех разделах — новый инженер читает незнакомый экран по тем же правилам, что и свой. Каркас держим в рамках конвенций Apple для актуальной ветки платформы.
Переиспользование экранов здесь работает не как копирование кода: типовые сценарии — авторизация, список, карточка, фильтры — вынесены в самостоятельные модули и подключаются к новому разделу без правок внутри. Объём нового кода на экран падает в разы, а поведение типовых блоков не расходится между разделами.
Изолированные слои дают предсказуемые проверки: логику тестируем отдельно от интерфейса и без запуска всего приложения. Доля путей, закрытых проверками, растёт, а дефекты на стыках модулей — самая дорогая категория по стоимости исправления — перестают доходить до релиза.
Режимы организации слоёв VIPER: сравнение подходов
Слои VIPER можно собрать по-разному, и разница видна не на первом экране, а на двадцатом — когда правка одного сценария тянет за собой View, Router и весь набор тестов. Ключевой вопрос: где проходят границы модулей и кто владеет контрактами — протоколами Presenter-а, Interactor-а и Router-а.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Ручные контракты внутри одного модуля | 2–5 экранов, короткий срок | Ручное копирование, слои расходятся, тесты дублируются |
| Генерация по шаблонам | Десятки однотипных экранов | Шаблон диктует структуру, генератор надо обновлять на живом проекте |
| Отдельно собираемые модули | Несколько команд, переиспользование | Дороже старт, строгие правила версий контракта |
| Общий слой контрактов и модулей | Крупный продукт с потоками | Без дисциплины общий слой разрастается |
Выбор идёт по двум осям: число экранов и число команд. Пока экранов немного, генерация по шаблонам убирает ручное копирование и фиксирует контракт в одном месте, но общий слой пока не нужен. Когда появляются независимые потоки и переиспользование, выносим модули за границу сборки и версионируем контракты.
Переход делается поэтапно, без переписывания: сначала вводим шаблон, затем выносим готовый модуль — слои остаются на месте, меняется только адрес контракта. Такой путь позволяет сравнить варианты на своём коде, а не на презентации.
Этапы перевода приложения на модульную схему
Перевод работающего приложения на модульную схему — не разовый рефакторинг, а последовательность шагов, где каждый заканчивается проверяемым результатом. Внедрение модульной схемы ведём волнами: сначала фиксируем текущее состояние, затем меняем один участок и убеждаемся, что поведение не поехало. Разработка при этом не останавливается — релизы продолжают выходить.
Порядок работ выглядит так.
- Аудит зависимостей. Собираем карту связей: где логика размещена в слое представления, какие классы тянут за собой половину проекта, где циклы и скрытые обращения к общему состоянию. На выходе — перечень узлов и очередность их распила.
- Схема модулей и план перевода. Определяем границы: что становится самостоятельным модулем, что уходит в общий слой, какие интерфейсы публичные. План перевода разбит на волны — по одному-два модуля за релиз, чтобы изменения оставались обозримыми.
- Настройка генераторов кода. Заводим шаблоны модуля — представление, интерактор, презентер, сущность, маршрутизатор — с едиными именами и структурой папок. Новый модуль создаётся командой, а не копированием соседнего, поэтому разнобой между участками не накапливается.
- Пилотный модуль. Один независимый участок переводим целиком по новой схеме и встраиваем в приложение без изменения поведения. Пилот показывает реальную стоимость шага и то, сколько времени экономят генераторы.
- Регрессионная проверка. Прогоняем автотесты на интеракторы и презентеры, проходим вручную критичные сценарии и сравниваем поведение до и после. Отдельно фиксируем время сборки и размер артефактов — по ним видно, что модульность работает, а не только описана.
- Передача документации и обучение команды. Отдаём схемы модулей, правила границ, чек-листы проверки кода и инструкцию по генераторам. Разбираем всё на живом коде, чтобы команда дальше переводила модули своими силами.
Что остаётся у команды после передачи проекта
Передача проекта — это не архив с исходным кодом, а набор артефактов, по которым команда заказчика продолжает работу без авторов. Всё перечисленное лежит в репозитории рядом с кодом и в регламентах: инженер читает их и берёт задачу в работу самостоятельно.
- Документация по модулям — назначение, входы и выходы, связи со слоями VIPER-модуля; видно, что можно менять изолированно, не задевая остальное приложение.
- Шаблоны и настройки генерации — заготовки модулей и конфигурация инструментов, создающих новый код по принятому стандарту; шаблон правится в одном месте, и следующие модули рождаются согласованными.
- Карта зависимостей — схема связей модулей, чтобы новый функционал не превращал архитектуру в клубок.
- Правила ревью кода — чек-лист проверяющего: границы слоёв, обработка ошибок, покрытие проверками, договорённости по именованию.
- Порядок выпуска версий — путь от ветки до публикации в магазинах приложений: кто подтверждает, как готовится описание изменений, как откатывается неудачный релиз.
- Инструкции для новых инженеров — окружение, точки входа, типовые задачи первой недели; выход на самостоятельные правки занимает дни, а не месяцы.
Отдельно фиксируем, кто в команде владеет каждым артефактом и когда он обновляется — иначе документация расходится с кодом уже через пару итераций.
Кейс: сократили время сборки и убрали класс отказов
Кейс мобильного приложения на Swift: к началу работ оно собиралось единой сборкой, где любой экран тянул за собой весь код. Правка в одном месте запускала пересборку всего проекта, и цикл проверки занимал минуты, которых у команды не было. Дороже обходились не сами задержки, а ошибки: большинство отказов всплывало не внутри экранов, а на стыках между слоями, где один слой дёргал другой напрямую.
Перевод на модули
Мы разложили приложение на слои по схеме VIPER — экран, взаимодействие, сущность, представление, маршрутизация — и зафиксировали контракты между ними. Генераторы кода создают каркас нового модуля и заготовки тестов, поэтому разработчик сразу пишет логику, а не воспроизводит однотипные файлы. Сборка стала инкрементальной: изменение в одном модуле не тянет за собой остальные.
Цифры до и после
Полная сборка сократилась втрое, сборка после типовой правки — с десятков секунд до единиц. Доля отказов на стыках модулей упала с 30% до 6%: контракты проверяются на этапе сборки, а не на тестировании и не на релизе. Трудозатраты на доработку нового экрана — 2 дня вместо 1,5 недель, потому что структура, навигация и тесты уже сгенерированы. Откат отдельного модуля теперь тоже не требует пересборки всего приложения.
Что делать, если монолит уже развёрнут и переписывать нельзя
Переписывать монолит целиком не нужно и почти всегда вредно. Вопрос не в том, можно ли ввести модульные слои, а в том, как делать это частями: новый код для iOS собирается по архитектуре VIPER, а старое ядро продолжает работать рядом и постепенно теряет вес.
Сосуществование старого и нового кода держится на границах модулей. У каждого нового экрана появляется собственный модуль, где представление, логика, навигация и работа с данными разведены и не знают друг о друге, а монолит вызывает его через тонкий интерфейс. Границы проводят там, где правки идут чаще всего, — именно эти участки дают отдачу первыми.
Выпуск версий при этом не останавливается. Один релиз добавляет один-два модуля и переводит одну-две унаследованные области, сборка и автотесты покрывают оба слоя одновременно, а откат возможен на уровне отдельной области, а не всего приложения. Уже первые поставки снижают долю правок, задевающих несвязанные части кода.
Постепенное внедрение модулей выигрывает у полного переписывания по рискам. При переписывании паритет с текущим поведением приходится восстанавливать по косвенным признакам, сроки растут, а старый код всё это время продолжает меняться и расходиться с новой веткой — выпуск откладывается до момента, когда готово сразу всё.
Поэтому поэтапная переработка планируется релизами: доля кода под модулями растёт, доля изменений в монолите падает, а объём первого этапа считается по числу областей с самой высокой частотой правок.
Технические сомнения: тесты, зависимости, найм под схему
Возражения к жёсткой слоистой схеме повторяются из проекта в проект: не усложнит ли она поддержку старого кода, не потребует ли отдельного инженера и сколько времени уйдёт на обучение команды. Отвечаем по существу.
Как тестировать слои по отдельности?
Презентер проверяется без интерфейса, интерактор — без сетевых вызовов: зависимости подменяются заглушками на границах протоколов. Логика сценариев покрывается быстрыми проверками, а тяжёлые сквозные прогоны остаются для сборки экрана целиком — набор тестов перестаёт расти вместе с проектом.
Что делать с зависимостями между модулями?
Модули общаются через объявленные контракты и фабрику, а не прямыми вызовами, а сборка зависимостей вынесена в отдельный слой. Замена или удаление модуля не тянет цепочку правок по всему проекту, а тот же экран переиспользуется в другом сценарии без копирования кода.
Нужен ли отдельный инженер под поддержку?
Как правило, нет. Правка локализуется в одном слое, поэтому задача достаётся тому, кто свободен, а не тому, кто «писал этот экран». Трудоёмкость поддержки падает ещё и потому, что не нужно держать в голове связи по всей кодовой базе. Старый код переводится на схему постепенно, по мере правок, без остановки релизов.
Как быстро новый разработчик входит в проект?
Первая правка в рабочей версии — в пределах первой недели: у каждого слоя одна зона ответственности, а генераторы кода собирают новый модуль по готовому шаблону. Правила и примеры зафиксированы в коротком внутреннем руководстве, поэтому обучение не держится на одном человеке.
Обсудим задачу и вернёмся с планом работ
Чтобы разговор был предметным, а не общим, к обращению полезно приложить то, что у вас уже есть. Готовить презентации не нужно — достаточно рабочего контекста, по которому видно реальный объём работ.
- описание продукта и ключевых пользовательских сценариев — хватит двух-трёх абзацев;
- текущее состояние кода: есть ли проект, на какой стадии, что мешает развивать его дальше;
- перечень экранов и переходов между ними — из него вырастает схема модулей под проект;
- требования к интеграциям: авторизация, платежи, аналитика, уведомления, офлайн-режим;
- ограничения по срокам и платформам, доступы к существующим репозиториям и учётным записям;
- как сейчас проходит выпуск: сборка, проверки, публикация в магазинах приложений.
После обращения мы разбираем ситуацию и возвращаемся с оценкой и планом работ. В плане — внедрение модульной схемы: каждый модуль закрывает один сценарий и не тянет за собой соседние, генераторы кода снимают рутину с типовых экранов, а поддержка мобильного приложения идёт по понятному регламенту выпуска.
Опишите задачу в удобном виде — вернёмся с оценкой и планом работ. Если кода ещё нет, это не помеха: схему модулей под проект соберём с нуля, под ваш продукт и вашу команду.







