Чому BLoC Flutter ламається на масштабуванні екранів
Архітектура BLoC у Flutter-застосунку майже завжди стартує чисто: один потік станів на екран, передбачувані переходи, тести на кожен сценарій. Проблеми починаються на масштабуванні, коли екранів десятки, а над фічею працює кілька людей.
Стан обростає полями під кожен новий кейс, події множаться, і ніхто вже не тримає в голові повну картину — зміни в одному блоці несподівано ламають сусідній екран.
Типовий збій — гонка подій. Користувач швидко перемикає фільтри, відповіді приходять не в тому порядку, і в стані застосунку осідає результат застарілого запиту.
Зовні це виглядає як «залиплий» список або дані не того екрана, а відтворюється нестабільно, тому баг живе в проді місяцями. Лікується це не латкою в одному місці, а дисципліною потоку подій: скасуванням застарілих операцій і явним власником актуального результату.
Друге джерело — неконтрольоване перемальовування віджетів. Коли стан блоку зберігає все підряд, будь-яка його зміна тягне за собою перебудову цілого піддерева, хоча змінився один рядок.
На слабких пристроях це помітно по просіданню відгуку й витраті батареї, а на масштабі — по зростанню часу збірки: чим більше зв'язків між блоками, тим довше компілюється й проганяється тестами проєкт.
Окремий біль — розростання станів. Один блок на екран перетворюється на звалище з десятків полів, частина з яких актуальна лише для конкретного сценарію. Тести стають крихкими, а новий інженер у команді витрачає дні, щоб зрозуміти, які переходи взагалі можливі.
Розбираємо, як це закривається на рівні архітектури Flutter — від розбиття станів до правил роботи з подіями.
Що дає вибудувана архітектура застосунку
Передбачувана збірка та релізний цикл
Розділення на шари — представлення, бізнес-логіка, робота з даними — прибирає головну причину довгих збірок: перезбирання всього модуля через правку в одному екрані. Коли стан екрана живе в окремому класі, а не розмазаний по віджетах, зміна зачіпає лише свою гілку.
На практиці це скорочує час збірки в рази та знімає ситуацію, коли дрібна правка в одному екрані ламає збірку всього застосунку.
Відновлення після збою та клас відмов
Потік подій і станів робить поведінку екрана відтворюваною: за логом видно, яка подія надійшла і в який стан перейшов інтерфейс. Час відновлення після збою падає з годин до хвилин — інженер не гадає, а бачить точку відмови.
Зникає цілий клас відмов інтерфейсу: розсинхрон даних на екрані, «залиплі» стани завантаження, загублені відповіді під час перемикання між екранами. Ці помилки не відтворюються вручну і раніше доходили до користувачів.
Стабільність релізів і ціна простою
Чим менше прихованих зв'язків між екранами, тим нижча вартість простою: збій локалізовано в одному шарі й не тягне за собою решту. Тести на бізнес-логіку пишуться без запуску інтерфейсу, тому зростає частка шляхів, покритих перевірками, а регресії ловляться до релізу, а не після.
Релізи стають передбачуваними — команда випускає частіше і з меншою кількістю відкатів, а нова функціональність додається без переписування сусідніх екранів.
Шари, стани та події: як влаштований BLoC Flutter
BLoC — це не «ще одна бібліотека керування станом», а спосіб розкласти застосунок на шари з одностороннім потоком даних. Подія надходить з інтерфейсу, блок обробляє її та видає новий стан, а віджет лише відмальовує те, що отримав.
Через це логіка перестає жити всередині екранів, її можна покрити тестами без запуску інтерфейсу, а відтворити збій — за послідовністю подій, а не за «впіймай момент».
Далі починається інженерна частина: як нарізати блоки. Нижче — три робочі схеми, між якими реально обирають на старті проєкту.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Єдиний потік на весь застосунок | Невеликий продукт, 3-5 екранів, один розробник | Будь-яка зміна тягне за собою весь граф станів, тести стають крихкими |
| Розділення блоків за фічами | Середні та великі застосунки, кілька команд | Потрібні чіткі межі модулів, інакше блоки починають знати одне про одного |
| Гібрид: блоки за фічами + локальний стан екрана | Екрани з формою, фільтрами, анімаціями | Потребує домовленості, що вважаємо спільним станом, а що — деталлю екрана |
Розділення блоків за фічами дає передбачувану ціну зміни: правка в оформленні замовлення не зачіпає каталог, а тести однієї фічі не падають через іншу. Гібрид знімає головний біль — не потрібно тягнути в спільний потік кожне натискання фільтра.
Локальний стан екрана живе у своєму віджеті й помирає разом з ним, а в блок іде лише те, що переживає перехід між екранами.
Конфігурація шарів важливіша за вибір бібліотеки. Ми фіксуємо, де закінчується доступ до даних і починається логіка, як блоки отримують залежності та що відбувається при повторній події, поки попередня ще в роботі. Це ті місця, де застосунки зазвичай «двоять» запити та втрачають стан при згортанні.
Етапи налаштування архітектури під ваш продукт
Починаємо з аудиту коду: дивимося, як зараз розділені шари, де бізнес-логіка просочується в інтерфейс, скільки станів живе в одному місці та які залежності тягнуться напряму у віджети.
За підсумками фіксуємо карту проблемних місць — вона визначає обсяг робіт і порядок змін, щоб не переписувати застосунок повністю.
Далі проєктуємо схему шарів: інтерфейс, стан, бізнес-логіка, доступ до даних. Для кожної події та стану визначаємо власника, прописуємо контракти між шарами та правила, за якими віджет не знає про мережу, а логіка не знає про розмітку.
Схема узгоджується з вами до початку правок — на цьому етапі дешевше змінити рішення, ніж потім код.
- Аудит коду — розбір поточної структури, точок зростання та зв'язності модулів, карта проблемних місць.
- Схема шарів — розподіл відповідальності між інтерфейсом, станом, логікою та даними, контракти між ними.
- Налаштування архітектури — впровадження BLoC-підходу, винесення логіки з віджетів, єдині правила обробки станів і помилок.
- Навантажувальна перевірка — прогін сценаріїв із частими оновленнями та великими списками, замір відгуку інтерфейсу та споживання пам'яті.
- Регламент розробки — правила іменування, межі шарів, шаблони для типових екранів, перевірки на рев'ю.
- Передача команді — навчання ваших розробників, розбір спірних місць, супровід перших задач за новими правилами.
Після налаштування проводимо навантажувальну перевірку: дивимося, як поводиться інтерфейс за частих оновлень стану, довгих списків і паралельних запитів. Якщо просідання залишаються — уточнюємо схему, а не маскуємо їх точковими правками. Результат — передбачувана поведінка екранів і зрозуміла точка, де шукати причину збою.
Завершуємо регламентом розробки та передачею команді: правила іменування, межі шарів, шаблони типових екранів, чек-ліст рев'ю.
Ваші розробники отримують не разову правку, а робочий стандарт — нові екрани збираються за ним без нашої участі, а підтримка не перетворюється на археологію по чужому коду.
Артефакти, які залишаються у вашої команди
Робота з архітектурою закінчується не презентацією, а набором файлів у вашому репозиторії. Нижче — що саме залишається у команди після налаштування BLoC-шару, щоб розробку можна було продовжувати без нас.
- Схема залежностей і шарів. Діаграма потоків даних між інтерфейсом, блоками, сховищем і зовнішніми сервісами — із зазначенням, де проходять межі й що кому дозволено знати. За нею новий розробник розуміє структуру проєкту за один вечір, а не за тиждень читання коду.
- Шаблони блоків. Готові заготовки під типові сценарії: завантаження списку, форма, пагінація, робота з кешем. Кожен шаблон — з подіями, станами та розбором, чому стан спроєктовано саме так.
- Правила обробки помилок. Єдиний регламент: які збої показуємо користувачеві, які йдуть у лог, де відбувається повтор запиту, як розділяються помилки мережі та бізнес-логіки. Це прибирає різнобій, коли кожен екран обробляє збій по-своєму.
- Документація архітектури. Опис шарів, домовленостей про іменування, правил розділення відповідальності та типових рішень з обґрунтуванням. Документ живе в репозиторії поруч із кодом і оновлюється разом із ним.
- Регламент рев'ю. Чек-ліст для перевірки змін: чи не протікає логіка в інтерфейс, чи не розростається стан, чи покриті нові сценарії тестами. Рев'ю стає передбачуваним, а не залежить від того, хто дивиться правки.
- Набір тестів на ключові блоки. Перевірки станів і переходів, які фіксують поведінку та захищають від регресій під час доопрацювань.
- Інструкція з підключення нових екранів. Покроковий порядок: як завести блок, зв'язати його з інтерфейсом, додати події та стани — щоб команда розширювала застосунок за єдиним зразком.
Ці артефакти — не звітність, а робочий інструмент: за ними онбордиться новий інженер, проводяться рев'ю та плануються доопрацювання. Опишіть вашу задачу — повернемося з оцінкою та планом, що увійде в передачу.
Кейс: як скоротили час збірки та прибрали зависання
Проєкт — застосунок доставки на Flutter з трьома командами в одному репозиторії.
До релізу другого року стан став проблемним: повна збірка займала 22 хвилини, тести тривали 14, а на екрані каталогу під навантаженням регулярно виникали збої інтерфейсу — блокування головного потоку під час перезбирання великих списків.
Кожен реліз виходив раз на три тижні, і половину часу команда витрачала на розбір регресій, а не на задачі.
Що змінили
Рознесли логіку за шарами: представлення, бізнес-логіка та дані перестали залежати одне від одного напряму. Стан екранів перевели на потоки подій — інтерфейс підписується лише на потрібний зріз і не перемальовує список повністю при точковій зміні.
Важкі операції — розбір відповідей сервера, підготовка даних для списків — винесли з головного потоку.
Окремо переробили збірку: увімкнули інкрементальну компіляцію та кеш залежностей між запусками, розділили проєкт на модулі, щоб правка в одному не тягла перезбирання всього.
Тести розбили на швидкі модульні та повний набір, який проганяється перед релізом, а не на кожне збереження.
Метрики до і після
| Показник | До | Після |
|---|---|---|
| Повна збірка | 22 хв | 7 хв |
| Прогін тестів | 14 хв | 4 хв |
| Частка релізів із збоями інтерфейсу | 40% | 6% |
| Цикл виходу релізу | 3 тижні | 5 днів |
Збої інтерфейсу перестали бути регулярними: з 30 релізів підряд лише два потребували термінового виправлення, і обидва — з зовнішніх причин, не через архітектуру.
Відкат на попередню версію тепер займає хвилини: збірка відтворювана, а стан екранів ізольовано, тому регресія не розповзається по всьому застосунку.
Що це дало команді
Релізний цикл скоротився втричі, і команда повернулася до продуктових задач замість постійної боротьби з падіннями. Новий розробник входить у проєкт за тиждень: структура передбачувана, а тести показують, що саме зламалося.
Далі масштабували той самий підхід на другий продукт — перенесення зайняло менше часу, бо архітектурні рішення вже перевірені на практиці.
Чим BLoC відрізняється від інших підходів до стану
BLoC — це підхід, у якому стан екрана описується не набором розрізнених змінних, а потоком подій і явними станами. Інтерфейс надсилає подію, логіка її обробляє та видає новий стан, а віджет лише відмальовує те, що надійшло.
Така однонаправлена схема прибирає клас помилок, де два місця в коді незалежно змінюють одні й ті самі дані та розходяться між собою.
Порівняння підходів до управління станом варто вести не за «модністю», а за тим, скільки логіки живе на екрані та як часто вона перевикористовується.
Локальний стан усередині віджета — найдешевший варіант, і для форми з пари полів або перемикача теми він залишається правильним.
Проблема починається, коли тими самими даними потрібно ділитися між екранами, переживати переходи та підвантажуватися з мережі: тоді стан розповзається по дереву віджетів, а налагодження перетворюється на пошук того, хто останнім перезаписав значення.
BLoC виправданий там, де логіка повторюється на кількох екранах, де важливий передбачуваний порядок оновлень і де бізнес-правила мають бути покриті тестами окремо від інтерфейсу.
Якщо застосунок складається зі статичних списків і простих переходів, повноцінний шар станів додасть коду більше, ніж користі.
Обмеження підходу чесно називаємо одразу: це більше файлів і церемоній на старті, вищий поріг входу для нових розробників, а на дрібних екранах — помітна перевага інфраструктури над задачею.
Окремо варто продумати, як події та стани лягають на навігацію й відновлення після згортання застосунку, інакше виграш у передбачуваності з'їдається ручною синхронізацією.
Вибір архітектури — це завжди компроміс між строгістю та швидкістю змін, і ми підбираємо його під конкретний продукт, а не за звичкою.
Часті технічні сумніви перед стартом
Технічні керівники рідко запитують «що таке BLoC» — вони запитують, що буде з їхньою кодовою базою. Нижче — питання, які ставлять найчастіше, і чесні відповіді без маркетингу.
У нас уже є застосунок на Flutter зі своєю архітектурою. Переписувати все заново?
Ні. BLoC вбудовується по екранах і модулях: спочатку виносимо в події та стани один-два критичні сценарії, решта коду продовжує працювати на попередній логіці.
Далі міграція йде ітераціями, кожна з яких проходить рев'ю та реліз окремо — без «великого переписування» і заморозки продукту на місяці.
Наскільки це сумісно з поточними бібліотеками та навігацією?
Шар представлення залишається попереднім — змінюється лише джерело стану. Навігація, теми, локалізація та мережевий шар підключаються до BLoC через ті самі інтерфейси, що й раніше.
Конфлікти можливі там, де логіка вже розмазана по віджетах: ці місця ми фіксуємо на етапі розбору коду і показуємо список до початку робіт.
Що з підтримкою після передачі проєкту?
Передаємо не лише код, а й правила: схему потоків даних, домовленості щодо іменування подій і станів, шаблони для типових екранів і чек-ліст код-рев'ю. Ваша команда додає новий екран за готовим зразком, не розбираючись у чужій логіці. Перший час залишаємося на зв'язку з конкретних питань.
Які ризики впровадження варто закласти заздалегідь?
Головний — зростання кількості станів на складних екранах, якщо не домовитися про межі модулів одразу. Другий — тести: без покриття подій і переходів рефакторинг стає небезпечним.
Обидва ризики знімаються на старті: фіксуємо контракти модулів і пишемо перевірки на ключові сценарії до того, як торкаємося робочого коду.
Чи можна відкотитися, якщо підхід не підійде?
Так. Поки міграція йде по модулях, кожен крок — окремий коміт з робочою попередньою версією. Якщо на якомусь екрані рішення не виправдало себе, повертаємо попередню реалізацію, не зачіпаючи решту застосунку.
Тому ми й не починаємо з повного переписування: ціна помилки на одному екрані непорівнянна з ціною помилки в усьому продукті.
Опишіть вашу кодову базу та те, що турбує в поточній архітектурі, — повернемося з оцінкою етапів міграції та планом перевірок.
Обговоримо ваше завдання і повернемося з планом
Розмову починаємо не з комерційної пропозиції, а з розбору вашого застосунку: як влаштований потік даних зараз, де стани розходяться з реальністю, які екрани страждають від зайвих перемальовувань.
За підсумками обговорення ви отримуєте не абстрактне «зробимо добре», а конкретний план переходу на BLoC з оцінкою термінів і складом команди.
Що уточнюємо на дзвінку:
- Поточну структуру застосунку: скільки екранів, які стани живуть локально, а які мають бути спільними для кількох розділів.
- Точки болю: де логіка розмазана по віджетах, де бізнес-правила дублюються, які збої відтворюються у користувачів.
- Вимоги до офлайн-режиму та синхронізації — від цього залежить, як проєктувати події та стани.
- Обмеження за термінами та релізами: чи є дата, до якої поточна версія має залишатися робочою.
- Хто на вашому боці ухвалює рішення щодо продукту і хто перевірятиме результат.
Що ви отримуєте за підсумками розмови:
- План робіт за етапами: аудит поточного коду, проєктування шарів, поетапне перенесення екранів, тести та випуск.
- Оцінку термінів з розбивкою за етапами — видно, де можна розпаралелити, а де потрібна послідовність.
- Склад команди під завдання: хто проєктує архітектуру, хто веде перенесення, хто відповідає за тести та реліз.
- Схему міграції без зупинки продукту: старі екрани продовжують працювати, поки нові проходять перевірку.
- Прозорі критерії готовності: покриття ключових сценаріїв тестами, відсутність розсинхрону станів, стабільні збірки.
Опишіть завдання у зручному вигляді — посиланням на репозиторій, списком проблемних місць або коротким повідомленням. Ми повернемося з оцінкою термінів, планом робіт і пропозицією щодо складу команди, щоб ви могли ухвалити рішення про старт проєкту.







