Из Java во Flutter: как я написала мобильное MVP за три месяца и что поняла
Меня зовут Милена, я бэкенд-инженер на Java в Банки.ру. Полтора года назад я взялась за задачу, которую обычно поручают отдельной мобильной команде: разработать приложение для продукта, где не было ни одного Flutter- или Android-разработчика. Через три месяца MVP вышло на обеих платформах. Заодно я наконец ответила на личный вопрос: хочу ли заниматься мобильной разработкой всерьез? Ответ оказался отрицательным, но сам опыт дал мне гораздо больше, чем я ожидала.
Почему мобильное приложение пришлось делать самостоятельно
В нашей продуктовой команде было семь человек: продакт, тимлид, тестировщик, два бэкенд-инженера и два фронтенд-разработчика. В какой-то момент продукту потребовалось мобильное приложение. В него планировали перенести часть возможностей сайта, а также добавить новые функции - например, календарь платежей, которого в веб-версии не было.
Набирать отдельную мобильную команду мы не стали. Для продукта, который еще только проверял свою востребованность, это выглядело слишком дорого и медленно. Нужно было быстро собрать рабочий MVP и понять, нужен ли он пользователям вообще.
Мы рассматривали React Native и Flutter. На первый взгляд логичнее выглядел React Native: в команде уже был фронтендер на React. Но переход к мобильной разработке все равно потребовал бы переобучения. У меня же сохранился небольшой опыт работы с Flutter - несколько лет назад я делала на нем дипломный проект. Кроме того, технология активно развивалась и казалась перспективной.
Я предложила написать приложение самостоятельно. На это повлияли две причины. Первая была практической: команде требовался человек, способный закрыть мобильное направление. Вторая - личной. Мне давно хотелось понять, насколько мне подходит мобильная разработка и могу ли я заниматься ею профессионально.
Дипломный проект не давал настоящего ответа. У него не было реальных пользователей, строгих требований к качеству и поддержки после релиза. Теперь предстояло сделать продукт, которым будут пользоваться люди, а значит, придется учитывать ошибки, производительность, удобство интерфейса и поведение приложения на разных устройствах.
Ответственность без мобильного наставника
Соглашаясь на задачу, я переживала не столько из-за самой технологии, сколько из-за отсутствия опытного мобильного разработчика рядом. Некому было посмотреть архитектуру и сказать: "Этот подход лучше переделать сейчас, иначе через месяц будет поздно".
Вся ответственность за технические решения оказывалась на мне. Нужно было самостоятельно выбирать библиотеки, продумывать структуру проекта, решать вопросы навигации, хранения состояния и взаимодействия с платформой. При этом энтузиазма все же было больше, чем страха: возможность получить настоящий продуктовый опыт казалась слишком ценной, чтобы от нее отказываться.
Старые знания помогли меньше, чем я рассчитывала. За несколько лет многое забылось, но проблема была не только в памяти. Еще во время диплома я понимала, что некоторые решения можно было принять лучше, однако сроки не позволяли переделывать проект. Поэтому в коммерческой разработке я не стала механически повторять прошлый опыт и начала заново разбираться с современными подходами.
Архитектура оказалась знакомой
Неожиданно легко далась архитектура. Бэкенд-разработчику уже знакомы репозитории, DTO, слои приложения, зависимости и разделение ответственности. Мне не пришлось изучать эти концепции с нуля - нужно было только понять, как они выражаются в Dart и Flutter.
Для управления состоянием мы выбрали Bloc. По сравнению с решением, которое я использовала в дипломе, порог входа оказался выше. Зато Bloc хорошо отделяет бизнес-логику от интерфейса. Это особенно помогло позже, когда количество экранов и пользовательских сценариев выросло.
На раннем этапе такая структура может показаться избыточной. Однако она быстро окупается: экран становится проще читать, логику легче тестировать, а изменения не затрагивают сразу все части приложения. Для MVP соблазн написать все прямо в виджетах очень велик, но именно так проект быстро превращается в трудноподдерживаемый набор исключений.
Самым сложным оказался интерфейс
Главное удивление ждало меня не в архитектуре, а в описании UI. Я привыкла к Java и строгой структуре кода: классы, методы, слои, четкие границы между компонентами. Во Flutter интерфейс строится как дерево виджетов.
Открываешь файл и видишь один виджет внутри другого: `Column`, `Expanded`, `Padding`, контейнеры, строки, условия и обработчики событий. В первые недели я буквально теряла взгляд в этой вложенности. Нужно было не только научиться читать чужой код, но и писать собственный так, чтобы через несколько месяцев его можно было без боли поддерживать.
Постепенно ситуация улучшилась. Помогли подсказки редактора, форматирование, вынос крупных частей в отдельные компоненты и привычка заранее продумывать структуру экрана. Но первое ощущение было таким, будто я попала на незнакомую планету.
Здесь важен не только технический навык, но и визуальное мышление. В мобильной разработке нельзя ограничиться вопросом "работает ли функция". Нужно постоянно учитывать, как выглядит экран на маленьком дисплее, что происходит при длинном тексте, как ведет себя клавиатура, что увидит пользователь во время загрузки и каким будет состояние после ошибки.
Состояние и навигация забрали больше всего времени
Если к структуре Flutter-проекта можно привыкнуть примерно за неделю, то управление состоянием потребовало значительно больше времени. Возникали вопросы, на которые не всегда удавалось быстро найти очевидный ответ:
- почему экран не перерисовался;
- почему событие обработалось раньше, чем ожидалось;
- почему после возврата назад состояние сбросилось;
- почему повторный запрос отправился дважды;
- почему после обновления данных часть интерфейса осталась в старом состоянии.
Именно на отладку таких ситуаций ушло больше всего часов. На бэкенде обычно проще увидеть последовательность действий: пришел запрос, выполнилась логика, вернулся ответ. В мобильном приложении поведение зависит еще и от жизненного цикла экранов, навигации, асинхронных операций, особенностей платформы и текущего состояния виджетов.
Поэтому состояние нужно проектировать заранее. Полезно явно разделять состояния загрузки, успешного результата, пустого ответа и ошибки. Чем меньше неявных переходов и скрытых зависимостей, тем проще понять, почему интерфейс повел себя именно так.
Экран календаря едва не остановил проект
Самым тяжелым экраном стал календарь платежей. На бумаге задача выглядела простой: показать даты, суммы и статус операций. На практике выяснилось, что календарь объединяет сразу несколько сложных областей - работу с датами, форматирование, фильтрацию, разные состояния ячеек, адаптацию под размер экрана и большое количество пограничных случаев.
Проблемы появлялись одна за другой. Что делать с часовыми поясами? Как отображать несколько операций в один день? Как обозначить текущую дату? Что показывать, если данных нет? Как вести себя при перелистывании месяцев? Как не сломать интерфейс на устройстве с небольшим экраном?
Именно на этом этапе я впервые всерьез подумала, не бросить ли проект. Казалось, что небольшой элемент интерфейса неожиданно стал отдельным продуктом. Спасло поэтапное упрощение требований: сначала мы реализовали базовый сценарий, затем добавили необходимые состояния и только после этого занялись визуальными деталями.
Этот опыт научил меня не пытаться сразу построить идеальный компонент. Для MVP важнее определить минимально полезную версию, проверить ее на реальных сценариях и лишь потом расширять.
Искусственный интеллект стал дополнительным наставником
Полноценного мобильного наставника у меня не было, поэтому часть консультаций я получала с помощью ИИ. Он помогал разбирать ошибки, объяснять незнакомые конструкции Dart, сравнивать варианты реализации и находить причины неожиданных перерисовок.
Однако использовать такие подсказки без проверки нельзя. ИИ может предложить решение, которое формально работает, но плохо вписывается в архитектуру проекта, устарело или создает проблемы на другом этапе. Поэтому я воспринимала его не как замену ревьюеру, а как собеседника для первичного анализа.
Лучше всего работал такой подход: сначала самостоятельно сформулировать проблему, затем попросить несколько вариантов решения, проверить их документацией и протестировать на небольшом примере. Это заметно ускоряло обучение, но не отменяло необходимости понимать, почему код устроен именно так.
Три месяца до релиза
Сроки были очень сжатыми: за три месяца требовалось выпустить приложение на двух платформах. Приходилось постоянно выбирать между идеальным решением и тем, которое достаточно хорошо закрывает пользовательскую задачу.
В MVP особенно важно не распыляться. Мы разделяли функции на обязательные и те, которые можно отложить. Такой подход позволил не утонуть в дополнительных настройках и не потратить весь срок на полировку второстепенных элементов.
Большую роль сыграла ранняя проверка на реальных устройствах. Эмулятор удобен для разработки, но он не показывает всех проблем: особенностей клавиатуры, системных разрешений, поведения при слабом интернете, размеров шрифтов и различий между версиями операционных систем.
Что пришлось изменить в рабочих привычках
Мобильная разработка заставила меня внимательнее относиться к мелочам. На сервере небольшая задержка или неидеальное состояние интерфейса часто остаются незаметными. В приложении пользователь сразу видит скачок экрана, пустой блок, неправильный отступ или бесконечный индикатор загрузки.
Я стала заранее продумывать не только основной сценарий, но и все промежуточные состояния:
- что отображается до получения ответа;
- что видит пользователь при отсутствии данных;
- как выглядит ошибка;
- можно ли повторить запрос;
- что произойдет при потере соединения;
- сохранится ли введенная информация после возврата на экран.
Еще один важный вывод - мобильное приложение нельзя оценивать только по коду. Его нужно регулярно запускать, нажимать, ломать и проверять в ситуациях, которые не описаны в идеальном пользовательском сценарии.
Понравилась ли мне мобильная разработка
После релиза я получила ответ на главный личный вопрос. Мобильная разработка оказалась полезным и насыщенным опытом, но заниматься ей постоянно я не захотела.
Мне не хватило привычной серверной модели, где основное внимание сосредоточено на данных, бизнес-правилах и взаимодействии сервисов. В мобильной разработке слишком много времени занимают визуальные детали, жизненный цикл экранов, особенности устройств и множество состояний интерфейса.
При этом я не считаю опыт неудачным. Наоборот, он помог лучше понять работу фронтенда и мобильных коллег. Теперь я яснее представляю, какие данные удобно отдавать клиенту, почему неудачный API усложняет интерфейс и насколько важны предсказуемые контракты между сервером и приложением.
Главные выводы
Первый вывод - отсутствие профильного специалиста не всегда блокирует запуск MVP, если задача ограничена, команда умеет быстро принимать решения, а требования не пытаются охватить все сразу.
Второй - знакомые архитектурные принципы переносятся между технологиями, но синтаксис и инструменты нельзя изучать поверхностно. Понимание слоев не избавляет от необходимости разбираться в жизненном цикле платформы и особенностях UI.
Третий - состояние нужно проектировать раньше, чем кажется. Большая часть сложностей появляется не при отображении данных, а при переходах между загрузкой, ошибкой, пустым результатом, повторным запросом и возвратом пользователя на экран.
Четвертый - MVP не означает небрежный продукт. У него может быть небольшой набор функций, но базовые сценарии должны быть надежными, понятными и проверенными на реальных устройствах.
И наконец, профессиональный эксперимент не обязан завершаться сменой специализации. Иногда результатом становится не новая карьерная траектория, а более точное понимание собственных интересов. Я попробовала мобильную разработку в настоящих условиях, довела приложение до релиза и теперь лучше понимаю, почему все-таки выбираю бэкенд.


