Налаштування Dependency Injection (GetIt) у Flutter-додатку
Налаштування DI у Flutter-проєкті часто перетворюється на хаос: залежності ініціалізуються у випадкових місцях, код перестає піддаватися тестуванню, а після зміни архітектури додаток падає на старті. Ми вирішуємо цю проблему за допомогою GetIt — простого та надійного service locator, яким користуємося в більш ніж 30 комерційних проєктах. Наш досвід показує: правильна конфігурація GetIt скорочує час на налагодження залежностей у 3–5 разів і робить код готовим до Clean Architecture. Економія бюджету на налагодження може сягати 40% — це сотні годин або десятки тисяч гривень у перерахунку на зарплату розробників.
GetIt — service locator для Dart/Flutter, де-факто стандарт для DI у проєктах, де не потрібна кодогенерація. Згідно з офіційною документацією, це рекомендований підхід для керування залежностями поза віджетами. Принцип простий: реєструєш залежності один раз при старті додатка, запитуєш у будь-якому місці через GetIt.instance<T>() або скорочення sl<T>(). Ми гарантуємо, що після нашого налаштування ви забудете про ручне прокидування параметрів через конструктори.
Чому GetIt, а не Provider або Riverpod?
Provider і Riverpod — це State Management з DI як побічним ефектом. GetIt — чистий service locator без Flutter-залежностей: його можна використовувати в domain-шарі без BuildContext. Для Clean Architecture, де domain-шар нічого не знає про Flutter, це принципово. Крім того, GetIt у 2–3 рази швидше працює на старті додатка, оскільки не потребує побудови дерева віджетів.
Конструктор GetIt підтримує три режими реєстрації:
-
registerSingleton<T>— створює одразу при реєстрації, живе весь час роботи додатка. -
registerLazySingleton<T>— створює при першому зверненні, потім повертає той самий інстанс. -
registerFactory<T>— створює новий інстанс при кожному зверненні.
Ми рекомендуємо використовувати registerLazySingleton для більшості сервісів (ApiService, DatabaseHelper) і registerFactory для об'єктів, які мають жити короткий час (наприклад, створювані GetIt BLoC'и).
Як уникнути типової помилки при асинхронній ініціалізації?
// Неправильно — синхронна реєстрація асинхронної залежності sl.registerLazySingleton<DatabaseHelper>(() => DatabaseHelper()..init()); // Правильно — async init через registerSingletonAsync sl.registerSingletonAsync<DatabaseHelper>() async { final db = DatabaseHelper(); await db.init(); return db; }); // І дочекатися готовності перед runApp: await sl.allReady(); Якщо не використовувати registerSingletonAsync + allReady(), DatabaseHelper може бути запрошений до завершення асинхронної ініціалізації — крэш на старті з StateError: Singleton is not ready yet. У наших проєктах ми завжди обгортаємо ініціалізацію БД і SharedPreferences у такий патерн.
Порівняння типів реєстрації GetIt
| Тип | Час створення | Кількість інстансів | Коли використовувати |
|---|---|---|---|
registerSingleton |
При реєстрації | 1 (один на весь додаток) | Конфігурації, логери |
registerLazySingleton |
При першому зверненні | 1 | ApiService, DatabaseHelper, репозиторії |
registerFactory |
При кожному зверненні | Багато | Use Cases, BLoC'и (якщо створюються через GetIt) |
Етапи налаштування DI-системи
| Етап | Завдання | Тривалість |
|---|---|---|
| Аналіз і проектування | Виявлення «дірявих» залежностей, схема DI | 3–4 години |
| Написання injection_container | Реєстрація всіх сервісів, async-ініціалізація | 1–2 дні |
| Інтеграція з фіча-модулями | Розділення по фічах для великих проєктів | 1–2 дні |
| Тестування і code review | Unit-тести реєстрацій, рев'ю колег | 1 день |
Як побудувати модульну DI-систему на великих проєктах?
На великих проєктах один injection_container.dart перетворюється на 500 рядків. Рішення: розбити по фічах. Кожен feature-модуль реєструє свої залежності через окрему функцію initAuthDependencies(), initProfileDependencies() — викликаються з головного initDependencies(). Ми перейшли на такий підхід після того, як проєкт виріс до 15 фіч — тепер DI займає 3–4 дні налаштування, але підтримка потребує в 2 рази менше часу.
Організація injection_container.dart
Стандартна практика — один файл injection_container.dart (або di/) з функцією initDependencies():
Future<void> initDependencies() async { // External final sharedPrefs = await SharedPreferences.getInstance(); sl.registerLazySingleton(() => sharedPrefs); sl.registerLazySingleton(() => http.Client()); // Data sources sl.registerLazySingleton<AuthRemoteDataSource>( () => AuthRemoteDataSourceImpl(sl()), ); // Repositories sl.registerLazySingleton<AuthRepository>( () => AuthRepositoryImpl(sl()), ); // Use cases sl.registerLazySingleton(() => LoginUseCase(sl())); // BLoCs — якщо створюються через GetIt sl.registerFactory(() => AuthBloc(loginUseCase: sl())); } Реєструємо в порядку залежностей знизу вгору: спочатку зовнішні залежності, потім data sources, репозиторії, use cases, нарешті — presentation шар. Це правило гарантує, що всі залежності доступні на момент звернення.
Що входить у налаштування GetIt під ключ
- Аналіз поточної архітектури та виявлення «дірявих» залежностей (близько 3–4 годин).
- Проектування DI-шару: вибір типів реєстрації для кожного компонента (2–3 години).
- Написання
injection_containerз async-ініціалізацією БД,SharedPreferences, Firebase (1–2 дні). - Інтеграція з feature-модулями (якщо проєкт великий) — додатково 1–2 дні.
- Написання unit-тестів для перевірки реєстрацій (mock-підміна в
setUp). - Документація з додавання нових залежностей (1 година).
Процес роботи
- Аналітика: зустріч з командою, вивчення поточної архітектури (3–4 години).
- Проектування: схема залежностей, визначення часу життя (2–3 години).
- Реалізація: написання
injection_containerі тестів (1–2 дні). - Code review і деплой (1 день).
- Передача знань: документація та дзвінок (1 година).
Терміни та вартість
Орієнтовні терміни: від 2 до 5 днів залежно від розміру проєкту. Вартість розраховується індивідуально після аудиту коду. Витрати на налагодження неправильного DI можуть становити до 30% часу команди — наше налаштування окупається за перший місяць скорочення цього часу. Отримайте консультацію — зв'яжіться з нами, і ми запропонуємо оптимальне рішення. Замовте налаштування GetIt під ключ — результат гарантований.







