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







