Налаштування Dependency Injection (Koin) в Android/KMM-додатку

Збої ініціалізації та приховані залежності в мобільному додатку гальмують випуск оновлень і лякають замовника раптовими відмовами. Ми налаштовуємо впровадження залежностей під ключ: вибудовуємо граф, усуваємо причини падінь і передаємо команді зрозумілі правила роботи. Після налаштування час на додавання нових модулів скорочується в рази, а клас відмов при запуску зникає.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Налаштування Dependency Injection (Koin) в Android/KMM-додатку
Простий
~2-3 дні
Часті запитання

Коли Koin DI у застосунку перетворюється на джерело збоїв

Koin DI зручний рівно до того моменту, поки граф залежностей вміщується в голові.

Щойно застосунок переростає десяток модулів, а KMM-модулі починають ділити спільний код між Android та iOS, розв'язання залежностей перетворюється на джерело відмов, які проявляються не на етапі збірки, а в рантаймі — у користувача.

Найчастіша причина падіння під час старту — циклічні залежності.

Koin розв'язує граф ліниво й у момент запиту, тому цикл не ламає компіляцію: застосунок збирається, проходить рев'ю, а потім падає на ініціалізації екрана або фонового сервісу, коли два компоненти посилаються один на одного.

Діагностика ускладнюється тим, що стек-трейс указує на точку запиту, а не на місце, де цикл було закладено.

Друга проблема — дублювання графів між модулями та платформами. Той самий репозиторій реєструється і в спільному KMM-модулі, і в платформеному, визначення перекривають одне одного, і в рантаймі підставляється не та реалізація.

На Android це дає різні екземпляри там, де очікувався один, на iOS — розходження поведінки з Android за формально спільного коду. Помилка не відтворюється стабільно й виринає як «плаваючий» баг.

Окремий клас збоїв — неявні залежності від порядку ініціалізації. Якщо модуль підвантажується пізніше, ніж відбувається перший запит, Koin не знаходить визначення й валить застосунок.

Розбираємо, як це закривається: перевіркою графа на етапі збірки, єдиною точкою реєстрації модулів і явними правилами для спільних KMM-модулів.

Що дає вибудуваний граф залежностей

Вибудуваний граф залежностей — це не про «модно», а про те, що відбувається із застосунком на старті.

Коли залежності збираються ліниво й по шарах, застосунок не тягне в пам'ять те, що не потрібне на першому екрані: час холодного старту скорочується на десятки відсотків, а на слабких пристроях різниця помітніша, ніж на флагманах.

Ми працюємо на Koin — декларативний граф читається як звичайний код, без генерації та рефлексії в рантаймі, тому збірка не обростає зайвими кроками.

Окремий біль — відмови ініціалізації. Коли залежності створюються вручну або через синглтони з побічними ефектами, падіння одного модуля валить весь старт: користувач бачить білий екран, а в логах — каскад помилок.

Явний граф із перевіркою на етапі збірки прибирає цей клас відмов: якщо залежність не оголошена або оголошена двічі, ми дізнаємося про це до релізу, а не зі звітів про аварії.

Для KMM-проєктів передбачуваність важливіша за швидкість. Спільний модуль описує контракти один раз, а платформенні частини підставляють свої реалізації — Android та iOS отримують однакову поведінку там, де логіка спільна, і не дублюють ініціалізацію. Це знімає цілий пласт розбіжностей, які зазвичай спливають на етапі приймання.

Швидкість збірки теж змінюється: без кодогенерації та з чітким розділенням модулів інкрементальна збірка йде швидше, а розробник не чекає на перезбірку графа після правки однієї залежності.

Підсумок — старт передбачуваний, відмови ініціалізації сходять нанівець на етапі збірки, а поведінка на обох платформах збігається.

Підходи до організації Koin DI: порівняння

Єдиний граф зручний на старті: один startKoin зі списком модулів, усе видно в одному місці.

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

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

Лінива ініціалізація змінює момент створення об'єкта: single створюється при першому зверненні, factory — на кожен запит, а важкі залежності (мережевий шар, база, аналітика) виносяться за межі стартового шляху.

Розділення за платформами критичне для мультиплатформених проєктів: спільний модуль описує контракти, а платформенні модулі підставляють реалізації через expect/actual — інакше спільний код починає тягнути залежності конкретної платформи.

Варіант Коли підходить Обмеження
Єдиний граф Невеликий застосунок, одна команда, короткий список екранів Правки в спільному файлі на кожну фічу, зростання часу старту, конфлікти при паралельній роботі
Модульна розбивка Кілька команд, зростаюча кількість фіч, незалежні релізи Потрібна дисципліна меж: протікання залежності між модулями ламає ізоляцію
Лінива ініціалізація Важкі залежності, чутливий холодний старт Помилки конфігурації спливають у рантаймі, а не при збірці — потрібні перевірки графа
Розділення за платформами Мультиплатформений проєкт, різні реалізації під платформи Дублювання оголошень, складніше відстежити, яка реалізація підставлена

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

Етапи налаштування Koin DI в проєкті

Налаштування впровадження залежностей в Android/KMM-проєкті — це не одноразова правка файлу, а послідовність кроків, де кожен наступний спирається на результат попереднього.

Якщо пропустити аудит або перевірку на одній із платформ, граф залежностей розповзається: частина об'єктів створюється двічі, частина залишається жорстко пов'язаною і не підмінюється в тестах. Нижче — порядок, за яким ми ведемо роботу.

  1. Аудит поточних залежностей. Проходимо по коду і фіксуємо, як об'єкти створюються зараз: ручні конструктори, статичні фабрики, звернення до спільних об'єктів напряму. Складаємо перелік того, що переводимо під управління контейнером, і позначаємо зв'язки, які доведеться розірвати.
  2. Проєктування схеми графа. Визначаємо, які об'єкти живуть увесь строк застосунку, які прив'язані до екрана, а які створюються на кожен виклик. Розкладаємо їх за областями видимості, щоб не тримати в пам'яті зайве і не плодити приховані зв'язки між шарами.
  3. Налаштування модулів. Описуємо модулі за шарами — дані, домен, представлення — і задаємо правила підстановки реалізацій. Спільні модулі виносимо в розділювану частину, платформенні описуємо окремо для Android і iOS.
  4. Перевірка на обох платформах. Збираємо і запускаємо застосунок на Android і iOS, перевіряємо, що граф будується однаково і платформенні реалізації підставляються коректно. Окремо проганяємо тести з підміною залежностей — так підтверджуємо, що зв'язки справді розірвані.
  5. Передача і документація. Фіксуємо схему графа, правила додавання нових залежностей і точки розширення. Передаємо команді замовника з розбором: де що лежить і як змінювати, не ламаючи решту.

Такий порядок дає передбачуваний результат: об'єкти створюються в одному місці, тести підмінюють залежності без правок бойового коду, а додавання нової платформи не вимагає переписувати граф. Опишіть задачу — повернемося з оцінкою та планом по вашому проєкту.

Артефакти після налаштування впровадження залежностей

На виході замовник отримує не «налаштований фреймворк», а комплект артефактів, за яким команда далі працює без автора впровадження. Кожен пункт — робочий файл або документ, а не переказ домовленостей.

  • Конфігурації модулів — розбиття графа на модулі за шарами (дані, домен, представлення) з явними точками входу: де оголошуються залежності, де підмінюються на тестові, де підключаються платформенні реалізації для Android і спільної частини.
  • Схема графа залежностей — візуальна карта: які компоненти від кого залежать, де створюється єдиний екземпляр, а де новий на кожен запит. За нею новий інженер за годину розуміє структуру, а не за тиждень читання коду.
  • Політики областей видимості — регламент, що живе в глобальній області, що прив'язано до екрана або сесії і коли звільняється. Закриває витоки пам'яті та «залиплі» стани між екранами.
  • Документація щодо впровадження — як додати нову залежність, як пов'язати модуль із платформенним кодом, типові помилки ініціалізації та їхні причини.
  • Регламент змін — правила правки графа: хто погоджує новий модуль, як перевіряється, що залежність не тягне зайвий шар, що робити при конфлікті областей видимості.
  • Набір перевірок — тести, що підтверджують, що граф збирається цілком і що підміна на тестові реалізації не ламає збірку.
  • Інструкція з передачі — порядок онбордингу: де лежать конфігурації, як запустити проєкт, до кого йти при розходженні схеми та коду.

Комплект самодостатній: команда може змінювати граф, додавати модулі та випускати релізи, не повертаючись до нас за кожним уточненням. Якщо щось у проєкті вже є — звіримо з цим списком і доповнимо відсутнє.

Кейс: усунення відмов ініціалізації в KMM-застосунку

Застосунок на Kotlin Multiplatform падав на старті у частини користувачів: граф залежностей збирався в рантаймі, і за певного порядку ініціалізації модулів виникала циклічна залежність між шаром даних і кешем.

Збій не відтворювався на стенді — лише на пристроях із холодним стартом і повільним диском, тому у звітах він виглядав як випадковий краш без стека.

Частка невдалих запусків трималася на рівні близько 4%, а підтримка витрачала на розбір повторюваних звернень більше часу, ніж на нові задачі.

Що змінили

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

Ініціалізація перестала залежати від порядку завантаження — тепер контейнер збирається детерміновано, а несправний зв'язок ловиться до викату.

Метрики до і після

Показник До Після
Частка збоїв при старті ~4% <0.2%
Час збірки проєкту базовий −18%
Час холодного старту базовий −22%
Розбір інцидентів ініціалізації регулярно поодинокі випадки

Скорочення часу збірки дав не сам DI-фреймворк, а відмова від рефлексії та зайвих модулів: граф став статичним, компілятор бачить зв'язки заздалегідь.

Команда Koin для нас тут — інструмент, а не самоціль: важливіше те, що відмови ініціалізації перестали бути класом проблем, який неможливо зловити до продакшену.

Якщо у вашому застосунку краші на старті списують на «плаваючий баг», найімовірніше річ у графі залежностей — опишіть задачу, повернемося з оцінкою та планом розбору.

Чим відрізняється Koin DI від ручного впровадження залежностей?

Ручне впровадження залежностей — це коли об'єкти створюються прямо в тому місці, де потрібні: екран сам збирає репозиторій, репозиторій — клієнт мережі, і так по ланцюжку.

На старті проєкту це виглядає нешкідливо, але кожна нова залежність вимагає правок у кількох місцях одночасно.

Як тільки з'являється другий варіант реалізації — наприклад, окреме джерело даних для тестів або інше середовище — доводиться або дублювати збірку, або додавати умови всередину робочого коду.

Koin DI переносить збірку об'єктів в окремий опис: залежності оголошуються один раз, а споживач запитує те, що йому потрібно, не знаючи, як це влаштовано всередині. Різниця проявляється на зростанні проєкту.

За ручного підходу додавання нового шару зачіпає всі точки створення, і чим більший застосунок, тим вищий ризик забути одну з них — помилка спливає не під час збірки, а в рантаймі, на конкретному сценарії в користувача.

Тестованість змінюється принципово. Ручна збірка змушує підміняти залежності через реальні конструктори, а отже тест тягне за собою весь ланцюжок — мережу, сховище, платформенні виклики.

З Koin достатньо перевизначити потрібне оголошення в тестовому модулі: підміняється один вузол, решта конфігурації залишається робочою. Тест стає швидким і не залежить від зовнішнього середовища.

Швидкість змін — другий ефект. Коли залежності описані декларативно, заміна реалізації або додавання прошарку — це правка одного оголошення, а не пошук по всьому коду. Команда перестає боятися чіпати пов'язані модулі, бо точки збірки зібрані в одному місці й видимі цілком.

Окремо варто сказати про межу застосовності. На невеликому застосунку з десятком класів ручне впровадження залишається робочим і не потребує додаткового шару.

Koin починає окупатися там, де з'являються кілька модулів, розділення за середовищами та регулярні зміни — саме на цьому масштабі ручна збірка перетворюється на джерело помилок, а не на економію.

Технічні сумніви щодо Koin DI

Впровадження DI-контейнера майже завжди впирається в ті самі інженерні сумніви: чи не доведеться переписувати робочий код, чи не виросте застосунок, як це живе в багатомодульному проєкті. Нижче — розбір за кожним пунктом.

Чи доведеться переписувати наявний код?

Ні. Koin підключається поверх поточної архітектури: модулі описують граф залежностей, а класи отримують їх через конструктор або делеговані властивості.

Уже працюючі екрани та шари даних мігрують поступово, по одному модулю за раз — старий спосіб створення об'єктів продовжує працювати паралельно, поки ви переносите наступну ділянку.

Наскільки виростає розмір застосунку?

Вплив на підсумковий артефакт мінімальний: контейнер не тягне генерацію коду на етапі збірки і не додає рефлексію в рантайм понад сам граф. Основний обсяг — описи модулів, які компілюються разом із застосунком. На практиці приріст непомітний на тлі бібліотек інтерфейсу та мережевого шару.

Як це працює в багатомодульному проєкті?

Кожен модуль оголошує власний набір залежностей і не знає про внутрішній устрій сусідів. Складальний модуль збирає їх у спільний граф, тому фіча-модулі залишаються ізольованими, а зв'язки між шарами видно в одному місці. Це спрощує і збірку, і паралельну роботу команд.

Що із сумісністю та відкатом?

Koin уживається з будь-яким UI-шаром і з уже використовуваними бібліотеками — конфліктів на рівні залежностей не виникає.

Якщо рішення не підійде, відкат зводиться до повернення попереднього способу створення об'єктів: граф ізольований в описах модулів і не прошитий по всьому коду. Тестові сценарії при цьому зберігаються — підміна залежностей на заглушки залишається такою ж простою.

Опишіть ваш проєкт — повернемося з оцінкою та планом міграції під вашу структуру модулів.

Обговоримо ваше завдання щодо Koin DI

Щоб повернутися з оцінкою та планом щодо Koin DI, нам потрібен не повний доступ до репозиторію, а картина вашого модуля впровадження залежностей: де створюються графи, як вони пов'язані з життєвим циклом екранів і що вже болить. Опишіть завдання у вільній формі — далі ми поставимо точкові запитання та запропонуємо план.

Що допомагає старту та прискорює оцінку:

  • структура модулів застосунку та межі спільного коду між Android і multiplatform-частиною;
  • поточний спосіб впровадження залежностей: ручні фабрики, service locator чи вже Koin — і на якому етапі він «поїхав»;
  • список сценаріїв, які ламаються: перестворення екрана, вкладена навігація, фонові задачі, тести;
  • як влаштовані області видимості — де потрібен singleton, де фабрика на екран, де залежність живе рівно один користувацький потік;
  • вимоги до тестів: які модулі підмінюються в перевірках і наскільки це зараз ручна робота;
  • обмеження за строками релізу та те, що не можна чіпати без зупинки продукту.

За цими даними ми зберемо план: розкладемо графи за модулями, визначимо порядок міграції без простою, зафіксуємо, як перевіряємо, що поведінка не змінилася. Якщо у вас є логи падінь або список відкритих дефектів, пов'язаних із залежностями, — додайте, вони уточнять оцінку.

Опишіть завдання та надішліть те, що вже є, — повернемося з оцінкою, планом робіт і порядком старту.

Наші компетенції:

Останні роботи

  • Розробка мобільного додатка для компанії FEEDME
    Розробка мобільного додатка для компанії FEEDME
    1010
  • Розробка мобільного додатку для компанії XOOMER
    Розробка мобільного додатку для компанії XOOMER
    903
  • Розробка мобільного додатку для компанії RHL
    Розробка мобільного додатку для компанії RHL
    1332
  • Розробка мобільного додатку для компанії ZIPPY
    Розробка мобільного додатку для компанії ZIPPY
    1180
  • Розробка мобільного додатку для компанії Affhome
    Розробка мобільного додатку для компанії Affhome
    1107
  • Розробка мобільного додатку для компанії FLAVORS
    Розробка мобільного додатку для компанії FLAVORS
    714