Авторизация
Забыли пароль?
Сброс пароля
Вернуться к авторизации

VisitTyumen: как мы спасли приложение с 15 000 ошибок в коде

09 сентября ‘25

Заказчик: ГАУ ТО «Агентство туризма и продвижения Тюменской области»
Страница кейса/результат: https://visittyumen.ru/

Когда проект попал к нам, встал выбор: начинать разработку с нуля или попытаться восстановить продукт. Мы пошли по второму пути и хотим рассказать, как превратили падающее приложение в стабильную платформу с приростом производительности на 50%.

Агентство-исполнитель кейса

WPP.DIGITAL (ex- WEB++)

WPP.DIGITAL — российское цифровое агентство разработки полезных IT-решений для retail и ecommerce.

1. Вводная задача от заказчика, проблематика, цели

Клиент обратился к нам, команде разработки IT-проектов WPP.DIGITAL, в начале 2022 года. Задачу он сформулировал предельно ясно: «спасти проект». На тот момент мобильное приложение состояло из основной части и двух-трех панелей администрирования с дублирующими действиями. Разработку продукта прежний подрядчик завершил в 2021 году, с тех пор приложение не поддерживалось и не обновлялось.

Василий Гребенников

директор, WPP.DIGITAL

Приложение падало постоянно, по словам заказчика — каждый день. Им приходилось заходить на сервер и вручную перезагружать систему, чтобы она работала. У разработчиков есть присказка, что проще все сжечь и написать с нуля. Но это не всегда правильно. Если каждая новая команда будет переписывать один и тот же продукт с нуля, бизнесу придется постоянно оплачивать одну и ту же работу. Поэтому лучше взять и разобраться

Сергей Тюрин

руководитель отдела mobile-разработки, WPP.DIGITAL

Хочется отдать должное команде заказчика — они очень часто предупреждали о предстоящих изменениях: "Сейчас будет изменение в этом модуле, проверьте, не повлияет ли оно на приложение". Мы обсуждали потенциальные риски и договаривались, что определенные элементы должны остаться неизменными — например, структура вложенности данных. С такими людьми работать приятно. Они заранее предупреждают о планах, дают нам время подготовиться. На других проектах случалось, что команды заказчика и разработчиков не могли найти общий язык — мы просили уведомлять об изменениях, но этого не происходило

2. Описание реализации кейса и творческого пути по поиску оптимального решения

Мы выбрали путь доработки, чтобы помочь клиенту сохранить вложенные инвестиции. Первоначально планировали исправить только мобильную часть (на это заложили около 500 рабочих часов), затем провели углубленный анализ и поняли, что придется оптимизировать и backend.

В первую очередь решили актуализировать версию фреймворка Flutter, на котором было построено приложение. Это решило бы критические проблемы с работоспособностью. А учитывая, что приложение уже было доступно пользователям, этот вопрос стоял особенно остро.

К моменту, как наша команда приступила к работе, возможности Flutter стали гораздо шире — появилась обработка исключений на пустые значения (null safety), новые виджеты, современные подходы к архитектуре.

Первая попытка актуализации фреймворка показала катастрофический масштаб проблемы. Мы выявили больше 8 тысяч ошибок. При этом каждое исправление порождало новые проблемы. Исправив одну часть кода, мы обнаруживали, что «летел» другой модуль. В итоге число ошибок выросло до 15 тысяч.

Поскольку клиент хотел получить стабильную версию как можно быстрее, мы решили «оживлять» приложение поэтапно и добавлять в магазины версии с рабочими модулями по мере готовности. Весь процесс восстановления можно условно разделить на 5 этапов.

Этап 1. Устранение критических ошибок и обновление основы

Самая трудоемкая часть работы заключалась в исправлении всех найденных ошибок. Встроенные средства Dart (язык программирования и разработки мобильных приложений) не справлялись с задачей из-за большого количества багов, поэтому разбираться с ними приходилось вручную. На это ушло около 2,5 недель.

Правок было просто нереальное количество. Можно сказать, что это был наш первый опыт оживления такого приложения. Раньше нам приходилось работать с проектами, которые не поддерживались максимум полгода, но там код читался хорошо, поэтому исправления вносились быстро. Здесь же масштаб проблем оказался совершенно иным.

После исправления основного массива ошибок мы попытались запустить приложение. Сначала отобразился заставочный экран, затем несколько экранов регистрации — выбор города, страны, общая информация. Это был прогресс.

Но с главным экраном возникли сложности. Из-за того, что приложение долго не поддерживалось, многие модули просто не загружали информацию. API тоже ушло далеко вперед, поэтому пришлось переписывать множество методов, которые делают запросы на сервер для получения данных.

Этап 2. Решение проблем совместимости и публикации

Параллельно с исправлением ошибок мы столкнулись с проблемой публикации в магазинах приложений. Google Play и App Store регулярно ужесточают политики безопасности, поэтому многие разрешения, которые использовало приложение в AndroidManifest и Info.plist, больше не поддерживались.

Магазины блокировали публикацию, требуя исключить устаревшие разрешения. При этом старые плагины нуждались именно в этих разрешениях для работы. Возникла дилемма: если оставить устаревшие версии плагинов — магазины будут блокировать публикацию, а если убрать разрешения — сломается функционал продукта. Мы решили не идти на компромиссы и обновить все плагины до актуальных версий, которые соответствуют новым требованиям безопасности Google и Apple.

Затем стали разбираться с базовой функцией регистрации — пользователи не могли войти в приложение через «ВКонтакте». Плагин, который использовала предыдущая команда, больше не поддерживался. У нас было 2 варианта: полностью переписать систему регистрации на новом плагине или локализовать существующий код. Мы выбрали второй путь — извлекли нужный код из устаревшего плагина, встроили его в приложение и отвязали от внешних зависимостей. Переписали нативную часть на Android, поправили код для iOS. Теперь приложение не зависит от версий плагинов и может поддерживать вход через «ВКонтакте» самостоятельно.

Этап 3. Архитектурная реконструкция

На этом этапе перед нами встала задача подключения к новой версии API. Начали с переделки раздела «места», и здесь обнаружилась серьезная архитектурная проблема. Предыдущие разработчики создали монолитную структуру — экраны с 3-4 тысячами строк кода, где одна функция могла дублироваться в нескольких местах.

Прежние подрядчики совершили глобальную ошибку — у них архитектура напоминает огромный монолит. Открываешь экран, там все красиво, затем открываешь тот же экран в коде — а там несколько тысяч строк. Мы оживляли экраны по отдельности. Проверяли каждый модуль и каждую кнопку, чтобы исправить все проблемы. Из 60 тысяч строк кода переписали 57 тысяч — практически каждую строку.

Раздел «места» пришлось полностью переписывать. Код прошел масштабный рефакторинг: мы разделили его на методы и классы, структурировали по папкам, чтобы улучшить читаемость. Параллельно интегрировали новую версию API, чтобы данные корректно синхронизировались с сайтом и админками.

Этап 4. Оптимизация производительности и интеграции

Приложение работало крайне неэффективно из-за устаревших подходов к управлению данными и их загрузке. Большая часть была написана на провайдере — классическом state-менеджере, подходящем для небольших приложений. Но когда речь идет об огромном объеме данных, которые грузятся сразу, приложение начинает потреблять слишком много памяти и вылетает.

Мы перешли на современный state-менеджер Flutter Bloc и одновременно внедрили плагинацию. Например, раньше страница с местами загружала все объекты сразу. Кэширование отсутствовало — каждый раз при заходе на экран информация загружалась заново. А для превью использовались изображения размером 1280 на 1100 пикселей.

Чтобы исправить это, договорились с backend-разработчиками о конвертации картинок на их стороне — они создали маленькие миниатюры. Внедрили кэширование изображений и пагинацию списков. Эти небольшие изменения помогли существенно увеличить производительность.

Особые сложности возникли с Google Картами — они отображались белыми и не показывали информацию. После многочисленных попыток исправить это мы перешли на «Яндекс.Карты» как более предсказуемое решение.

Этап 5. Тестирование и стабилизация

Работа над проектом шла быстро, но из-за сжатых сроков иногда мы пропускали мелкие ошибки, которые не выявлял анализатор кода. Например: при нажатии на кнопку дважды происходил переход на одну и ту же страницу, при покупке экскурсии не считалось количество билетов. Такие баги не критичны для работы приложения, но мешают пользователям.

Часто бывало, что мы такие баги замечали, когда уже готовились выкатывать обновление в прод. К нам тестер довольный подбегает и говорит, что нашел еще один баг, давайте переделывать. И вот так много раз было. То есть находили баги, исправляли и публиковали, потом находили еще, правили — снова публиковали.

Чтобы избежать нештатных ситуаций, команда мобильной разработки выстроила систему регресс-тестирования и написала множество проверок. Каждый модуль получил защиту от проблем. Например, если данные поступают в некорректном формате — специальная функция перерабатывает их в нужный вид.

После долгого отсутствия обновлений мы выпустили версию, в которой практически не осталось багов. Когда удостоверились, что версия работает стабильно, на стороне backend выкатили специальную фичу — при заходе в приложение появлялся попап с просьбой обновить версию. Так мы сообщили пользователям, что новая стабильная версия готова.

С тех пор критических багов больше не возникало. Происходили только мелкие доработки — поправить стили, изменить размеры элементов интерфейса.

3. Результаты сотрудничества

Основная разработка заняла 5 месяцев. На пике в команду входили 4 разработчика, в том числе технический лид, которые работали с 8 утра до 10 вечера.

Первую стабильную версию мы выпустили в июне 2022 года. По сравнению с первоначальной версией производительность приложения (скорость отрисовки виджетов, прогрузки экранов, загрузки/обновления данных из API) выросла на 50%. Четверть прироста дало обновление Flutter, остальное — архитектурные улучшения.

Отдельно стоит отметить качество взаимодействия с командой заказчика. Они предупреждали обо всех предстоящих изменениях, что позволяло заранее подготовиться и избежать лишних проблем.

Стабильная работа приложения стала главным достижением проекта, но вместе с этим мы улучшили и пользовательский опыт, отделив UI от логики. Теперь экраны открываются с уже готовой информацией и пользователи не сталкиваются с дополнительными загрузками.

Когда основные модули заработали стабильно, команда уменьшилась до 2 человек для спокойного развития проекта. В декабре 2024 года мы добавили новую крупную фичу — карты с кластеризацией и фильтрацией объектов. В планах заказчика — интеграция VR-технологий.

Сейчас приложение находится на горячей поддержке. Для заказчика такой подход оказался выгодным: ему не нужно тратить ресурсы на поиск нового подрядчика и ждать, когда новая команда сможет разобраться в продукте.

4. Заключение

Работа с унаследованными системами — непростой вызов для любой команды разработки. Такие проекты требуют особого подхода к планированию.

Главный урок — важность реалистичной оценки на старте. Наша первоначальная оценка в 500 часов выросла в несколько раз, когда стал понятен реальный масштаб исправлений. Если сроки позволяют, то детальный аудит кода застрахует от неприятных сюрпризов.

Архитектурные проблемы в устаревших приложениях также часто оказывают глубже, чем кажется на первый взгляд. Например, в VisitTyumen одна функция дублировалась в нескольких местах, что требовало многократных изменений. В этом случае хорошим инструментом служит поэтапный рефакторинг.

Проект VisitTyumen стал ценным опытом работы с legacy-системами. Мы научились правильно оценивать масштаб проблем, планировать поэтапное восстановление и поддерживать качество разработки при сжатых сроках.

Агентство-исполнитель кейса

WPP.DIGITAL (ex- WEB++)

WPP.DIGITAL — российское цифровое агентство разработки полезных IT-решений для retail и ecommerce.