Итак, здравствуйте! Меня зовут Никита Синявин, я разработчик мобильных приложений и лид команды Flutter-разработчиков в компании BetBoom. Также я веду свой личный блог, развиваю фреймворк для реализации подхода BDUI во Flutter, и являюсь администратором сообщества мобильных разработчиков Mobile Broadcast | Калининград.
React Native - Historia morbi
Критически важная проблема, с которой сталкивались наши пользователи при использовании мобильного приложения (далее МП) – это проблемы с производительностью на слабых устройствах.
В ходе профилирования мы выяснили неприятный факт: релизная сборка iOS приложения использовала в среднем 150 мб оперативной памяти, а Android в свою очередь, почти в два раза больше – до 300 мб. Учитывая тот факт, что у пользователя, скорее всего, в момент времени открыты и используют ресурсы устройства не одно приложение, то такая нагрузка может стать критической и вызвать ухудшение общей производительности приложения.
Еще одна боль, которую можно отнести к проблеме перформанса, – пресловутый FPS. Мы множество раз пытались оптимизировать наши компоненты в приложении, но зачастую это не помогало. Помимо обычных реакт-компонентов наше приложение было обильно сдобрено упоротыми зацикленными анимациями (включая lottie анимации) и разными красивыми UI-плюшками, которые создавали массу проблем.
Вторая проблема, которую мы видели в нашем МП, – большое количество зависимостей, которые тянут за собой ошибки при компиляции нативного кода. Думаю, каждый React Native разработчик регулярно сталкивается с проблемами сборки приложений при обновлении зависимостей. Хоть решение этих траблов и не занимает много времени, но становясь рутиной, на круг потраченное время приобретает представительный объем.
Масла в огонь истории с зависимостями подливала новая архитектура React Native, которая стала доступна в рамках эксперимента в версии 0.68. Обещания улучшения производительности фреймворка, признаюсь, нас вдохновили. Уже в тот момент мы инициировали процесс перехода на new arch, но столкнулись с не зависящими от нас трудностями: не все авторы библиотек спешили переписывать свои проекты. Да, в ходе работы эти библиотеки не отваливались, но и не давали обещанного профита, ведь работали в режиме обратной совместимости. Сейчас последняя версия RN 0.74, а компания-разработчик фреймворка заявила, что перевела свои приложения на новую архитектуру (еще бы не перевела), но мое мнение остается неизменным – обещанная “таблетка” для RN еще слишком сырая.
Такие прискорбные выводы относительно нашего главного инструмента заставили нас всерьез задуматься над альтернативами, в числе которых была разработка нативных приложений, мультиплатформа на базе KMP, а также герой нашей статьи – Flutter. Но почему мы выбрали именно его? Давайте разбираться!
Почему Flutter?
Для того, чтобы полноценно понять ход мыслей нашей команды, необходимо дать несколько вводных:
в рамках BetBoom наш проект не основной. Из этого вытекает факт, что мобильная команда совсем небольшая, а ресурсы ограничены;
наша команда разработки МП обладала в основном компетенциями в React Native.
Из этих двух пунктов вытекают несколько основных требований к новой технологии:
переход возможно осуществить силами команды в текущем составе;
временные рамки, необходимые для освоения стека не должны быть слишком большими;
новая технология не должна создавать бОльших накладных расходов на поддержку МП;
“переиспользование” компетенций. Желательно, чтобы мы могли использовать накопленный опыт на новом стеке.
C такими вводным Flutter стал для нас палочкой-выручалочкой и закрыл большинство наших требований. Во-первых, cо многими концепциями Dart мы были знакомы благодаря опыту с JS и TypeScript (например работа с асинхронностью и система типов). Во-вторых, это кроссплатформенная технология, которая позволит нам продолжить писать код в знакомой нам парадигме. И, в-третьих, нам не требовалось расширять текущую команду, мы чувствовали в себе силы на то, чтобы решить эту проблему с текущими ресурсами.
Процесс перехода – как это было?
Мало найти консенсус в команде, требуется также убедить в необходимости нашего решения представителей бизнеса, отодвинуть релиз редизайна МП и слить часть уже потраченных усилий на рефакторинг React Native приложения. И нам дали такой шанс!
Для проверки гипотезы мы не стали мудрить: выбор пал на самый нагруженный функционалом и анимациями экран приложений, который мог бы стать ярким примером улучшения ситуации (или наоборот).
Первую неделю нашей работы отняло изучение документации фреймворка и выработка архитектурной методологии, согласно которой мы будем строить новое приложение. В качестве стейт-менеджера мы выбрали BLoC, поскольку паттерн хорошо документирован и предлагает готовые решения для его реализации на Flutter.
Далее начался процесс верстки экрана и виджетов, который по началу доставил нам немало хлопот. Принципиально другой способ разметки сперва доставлял нам много проблем. Приходилось вникать в то, как виджеты Flutter получают свои размеры и констрейнты. Часто мы сталкивались с ошибками в виде hasSize и прочих ошибок, которые мы допускали при построении UI. Решения этого периода до сих пор встречаются в проекте. Они отличаются уродством и изобретательностью, но со временем мы вывели для себя подходящие нам методики создания удобных в поддержке, расширяемых и “резиновых” виджетов, а ошибки верстки практически канули в лету.
Второй важной для нас частью разработки стала мощная поддержка ООП в Dart. Тут наш сумрачный инженерный гений развернулся во всю ширь! Благодаря этому мы заложили устойчивую систему расширяемых сервисов, которые решают задачи управления бизнес-логикой приложения, сетевыми запросами, работой с БД и тд.
Спустя месяц работы были видны первые результаты. Хотя большинство данных для работы приложения и были моками, мы заметили существенный прирост FPS, а самое главное – бОльшую стабильность отрисовки, несмотря на обилие зацикленных анимаций и сложных элементов UI.
Настолько неожиданно высокий скачок в основных наблюдаемых показателях не оставил бизнесу и шанса – наша инициатива была принята в работу, и вот уже год мы пишем на Flutter! Мы развиваем многомодульную архитектуру проекта для решения проблемы дублирования кода приложений, которые выпускаются на рынки разных стран, вводим практику автоматизированного тестирования на проекте и стоим на пороге внедрения передовых технологических решений в области проектирования UI.
Что мы приобрели, начав использовать Flutter
Быстрый переход на новый стек в связи с тем, что команда была опосредованно знакома с фундаментальными принципами работы языка Dart.
Развитый туллинг “из коробки”. Приятным бонусом к технологии идет обширный туллинг для дебага и профилирования приложений.
Flutter – гибкая и глубоко кастомизируемая платформа, позволяющая использовать единый исходный код не только для создания мобильных приложений, но и для платформ Web и Desktop. А развитый механизм двунаправленного асинхронного взаимодействия с нативным кодом (и с библиотеками на C/C++ с помощью dart ffi), не ограничивает команду в реализации сложных технических решений.
Ложка дёгтя
Но не все оказалось так гладко в нашем плане. Если раньше мы могли доставлять хотфиксы и обновления пользователям через CodePush без необходимости обновления приложения через сторы, то перейдя на Flutter мы эту возможность утратили. Многие мне скажут, что есть Shorebird. Но по ряду причин эта технология нас не устраивала. Такой вот trade-off :)
Сейчас наша команда находится на длинном и тернистом пути решения этой задачи. Было принято стратегическое решение – развивать BDUI направление и интегрировать эту практику в нашу повседневную разработку.
Вместо выводов
Нашей команде удалось без лишней крови получить в свои руки один из мощнейших на текущий момент инструмент для кроссплатформенной разработки приложений. Но радоваться еще рано, впереди еще много открытий и точек роста наших инженерных навыков, чему мы очень рады.
Подводя итоги сказанного выше отдельно хочется отметить обширную документацию Dart/Flutter и количество учебных материалов по теме, высокое качество популярных библиотек, а также открытое экспертное сообщество, которое сформировалось за время существования фреймворка.
Был ли у вас опыт подобной миграции с другой технологии? Расскажите об этом в комментариях!
И конечно же:
Подписывайтесь на блог компании BetBoom на Хабре
Станьте частью сообщества мобильных разработчиков Mobile Broadcast
Подписывайтесь на мой телеграм-канал Boltology Tech