Java-бэкенд-инженер Банки.ру за три месяца собрала мобильное MVP на Flutter для команды, в которой вообще не было мобильных разработчиков. История цепляет не героизмом ради героизма, а честным выводом: кроссплатформенный стек действительно помогает быстро проверить продуктовую гипотезу, но не отменяет архитектурных рисков, платформенных сюрпризов и банальной усталости человека, который тащит все это в одиночку.
Об этом, как пишет Habr / Карьера, рассказала бэкенд-инженер Милена из Банки.ру. Полтора года назад ее продуктовой команде понадобилось мобильное приложение: нужно было перенести часть функций с сайта и добавить то, чего на вебе не было, например календарь платежей. Команда была компактной, семь человек: продакт, тимлид, тестировщик, два бэкендера и два фронтендера. Нанимать отдельную мобильную команду под продукт, который еще проверял себя, не стали: долго и дорого. В качестве компромисса выбирали между React Native и Flutter. Логика у React Native была очевидная, потому что в команде уже был фронтендер на React, но Милена предложила взять Flutter и написать приложение самой: у нее оставался небольшой опыт с дипломного проекта, а заодно хотелось понять, нравится ли ей мобильная разработка всерьез, а не в режиме студенческого эксперимента.
Сам по себе этот кейс хорошо описывает знакомую для рынка ситуацию. У продукта появляется запрос на мобильный канал раньше, чем появляется бюджет на полноценную мобильную вертикаль. Дальше начинается инженерная экономика: либо откладывать запуск, либо собирать MVP на кроссплатформе силами тех, кто уже есть в команде. В теории идея выглядит здраво. Один код, две платформы, быстрый выход в сторы, минимальные затраты на найм. На практике в истории Банки.ру важна именно разница между ожиданиями и реальностью. Милена прямо пишет, что самым тревожным для нее был не сам незнакомый стек, а отсутствие рядом опытного мобильного разработчика, который мог бы вовремя остановить плохое архитектурное решение. Для любого техлида это, пожалуй, центральная мысль всего рассказа: кроссплатформенный фреймворк сокращает стоимость входа, но не заменяет носителя экспертизы.
С архитектурой, по словам автора, проблем оказалось меньше, чем можно было ожидать. Бэкендеру не нужно заново объяснять смысл репозиториев, DTO и dependency injection: меняется синтаксис и инструменты, но не базовая инженерная логика. Для управления состоянием в приложении взяли Bloc. Выбор был не самым простым по порогу входа, зато помогал не смешивать UI и бизнес-логику, что быстро стало критично по мере роста количества экранов. И вот здесь история резко выходит за пределы привычного разговора про «универсального разработчика, который может все». Архитектурные паттерны и слои действительно переносятся между платформами. А вот ощущение среды, поведение интерфейса, работа жизненного цикла приложения и странности состояния не переносятся почти никак. Для человека с серверным бэкграундом это уже не просто новый фреймворк, а новая физика.
Где Flutter заканчивается и начинается настоящая мобильная разработка
Самым непривычным для Милены оказался не код как таковой, а способ описания интерфейса во Flutter: виджеты, вложенные друг в друга, дерево, в котором поначалу буквально теряешься глазами. Но настоящая боль началась на управлении состоянием. Почему экран не обновился, почему событие обработалось не в тот момент, почему после возврата назад состояние сбросилось, хотя, кажется, не должно было, — именно на такие вопросы ушли основные часы отладки. Еще один холодный душ: единая кодовая база не означает автоматически одинаковое поведение на Android и iOS. Большую часть времени приложение работает похоже, но затем всплывают различия платформ, библиотек и жизненного цикла. Это важный практический вывод для команд, которые смотрят на Flutter или React Native как на способ «не думать про натив». Думать все равно придется, просто чуть позже и, как правило, в самый неудобный момент.
Самой тяжелой частью проекта стал календарь платежей. Первые экраны, по воспоминаниям автора, шли довольно бодро, что создало приятную, но обманчивую иллюзию контроля. Затем появился календарь, и началась типичная для сложного клиентского состояния карусель: чинишь одну фичу, ломаешь другую; QA нажимает чуть не туда, и после повторного входа на экран все снова разваливается. Часть этого кода писал фронтенд-инженер, который подключился помочь, а чтение сложного чужого кода на языке, который ты сама только осваиваешь, автор описывает без романтики. В серверной разработке, замечает она, сценарии часто линейнее; в мобильном приложении пользователь постоянно выходит, возвращается, сворачивает экран, меняет контекст, и состояние должно переживать все эти маневры. Календарь пришлось доводить итерация за итерацией, без красивого инсайта и без одного волшебного фикса, просто баг за багом, пока очередь наконец не закончилась.
Похожая история случилась и с авторизацией через Telegram-бота, которую переносили с веба. В браузере можно держать вкладку открытой, а в мобильном сценарии пользователь сворачивает приложение и уходит в другой интерфейс. За это время SSE-соединение обрывалось, поэтому пришлось менять уже существующий процесс и адаптировать под него Telegram-бота. Для бизнеса тут лежит очевидный, но часто недооцененный вывод: мобильное MVP редко бывает просто «тем же самым, что веб, только на телефоне». Даже если функционально идея совпадает, пользовательские сценарии и технические ограничения быстро заставляют пересобирать процесс, который на десктопе казался нормальным.
ИИ как напарник, но не как техлид
Отдельный слой этой истории — использование ИИ в роли наставника. Поскольку в команде не было Flutter-разработчика, Милена опиралась на купленный курс и на ИИ-инструменты. Причем, по ее оценке, полезнее они были не там, где нужно было просто сгенерировать код, а там, где хотелось понять принятые практики: как обычно делают dependency injection, чем заменяют куки в мобильном приложении, почему один подход уместнее другого. Эффективность была далека от магии: по субъективной оценке автора, полезным оказывался примерно каждый второй ответ, плюс-минус в пропорции 60 на 40. Остальное приходилось перепроверять и чистить вручную, потому что сгенерированный код сам приносил баги. Это, пожалуй, самая взрослая часть материала. ИИ может ускорить исследование незнакомой технологии и снять часть рутинной нагрузки, но он не знает контекст команды, не чувствует границы проекта и не приходит с инициативой в нужный момент. То есть это хороший собеседник и посредственный сеньор.
Финальный вывод Милены для многих окажется даже полезнее всей технической части: ответ на личный вопрос «нравится ли мне мобильная разработка» оказался отрицательным. И это не провал, а нормальный результат хорошо поставленного эксперимента. За три месяца команда получила приложение на двух платформах, продукт — проверку гипотезы, а инженер — ясность, в какую сторону ей интересно развиваться, а в какую нет. Для рынка, где от разработчиков все чаще ждут универсальности, такая честность ценнее очередной истории про бесконечный growth mindset. Не каждый сильный бэкендер обязан полюбить mobile, как и не каждый mobile-инженер мечтает уйти в backend. Но почти любой команде полезно помнить другое: если вы запускаете мобильное MVP на Flutter силами людей без профильного опыта, закладывать нужно не только скорость старта, но и цену за обучение, ошибки состояния, платформенные различия и доработку сценариев, которые на вебе казались уже решенными.