Технический аудит системы для одного из крупнейших российских туроператоров
Проанализировали сервис для поиска туров, выявили проблемы производительности, приоритезировали их и выдали заказчику план улучшения сервиса с расчетом времени на фиксацию каждой из проблем, чтобы можно было прозрачно и понятно перейти к их устранению.
Дано
Сервис по поиску, бронированию и покупке туров со среднемесячной нагрузкой около 3 млн пользователей. Заказчик – один из лидеров рынка. Продуктовая команда выяснила, что сервис стал работать медленнее, чем у конкурентов: при одинаковом принципе работы отображение результатов поиска туров и следующие пользовательские шаги проходят с отставанием по скорости, что стали замечать в том числе и пользователи ресурса. Конверсия сервиса снизилась, а адаптивная версия сайта для мобильных устройств стала выдавать показатели ниже ожидаемых.
Продуктовая команда заказчика была загружена, глаз специалистов слегка замылен ввиду длительной работы над продуктом. Времени на выявление проблем и поиск их решений не было, поэтому заказчик решил обратиться за сторонней экспертизой к нам.
Стек системы:
- Фронтенд — Vue и Laravel (bff)
- Бекенд — C#, админка (гео) — Laravel
Основные фокусы, к которым приступили к работе
Команда заказчика при описании общих проблем с показателями загрузки своего сервиса отметила, что при загрузке выявляли сторонние скрипты, причины появления которых нуждались в уточнении. Мы сработали проактивно и уже к первым установочным встречам выдвинули несколько предположений об этой проблеме. Так, определили несколько ключевых направлений выявления проблем производительности сервиса:
- Исправить некорректную работу или подключение аналитических сервисов (появление сторонних скриптов), а именно:
- На странице поиска (результатов) отправляется около 200 обращений в вебвизор, хотя на сайтах конкурентов, по наблюдению команды, меньше.
- Google Tag Manager вызывает проблемы при работе сервиса. Возможно он не правильно подключен, а, возможно, в нем подключено много событий, которые отслеживает команда. При отключении GTM наблюдается прирост производительности в 2 раза.
- Возможные проблемы с другими аналитическими сервисами.
- Разобраться с событиями, которые вызываются при работе сайта.
- Ошибки в консоли — локализовать и предложить их исправление.
- Определение возможности переноса событий, которые JS отправляет в Google Analytics, на сторону GTM.
- Локализовать дополнительные проблемы и предложить решения по их устранению/улучшению.
Как мы работали
- Первым этапом мы провели встречи с командой заказчика, чтобы зафиксировать понимание задачи. Это обязательный процесс на всех наших проектах, и подробнее о нем мы рассказали в отдельной статье.
- После фиксации понимания задачи переходим к описанию задач, которые видим для решения проблем заказчика, описываем границы проекта и план аудита.
- Когда все ожидания согласованы, переходим к самому аудиту, полноценные работы по которому мы распределили на 4 недели.
О более верхнеуровневом видении аудита, понимании того, когда его нужно проводить, и наших подходах к этому процессу рассказали в отдельном материале.
Что проверяли и делали в ходе аудита для выявления и фиксирования проблем производительности системы
Сначала нужно было провести общую техническую оценку перфоманса системы в рамках трех разделов: главная, поиск, страница отеля. Это первый этап, без которого нет смысла лезть в код или анализировать работу сторонних сервисов.
Следующим шагом мы локализуем проблемы, которые удалось найти и выясняем, какие процессы или интеграции в системе повлекли их возникновение. На этом этапе постепенно погружаемся в кодовую базу системы: просматриваем, как ведут себя процессы с точки зрения исполнения кода, отсматриваем блокеры производительности.
Также серьезной проблемой была загрузка большого количества данных на странице поиска. Это сильно блокировало загрузку страницы.
Когда все аналитические задачи были выполнены, мы составили таблицу с выявленными проблемами и способами их решения с указанием часов работы для этого. В этом, на наш взгляд, отличие качественного технического аудита: важно не просто обозначить проблемы, но и выяснить их природу, для того, чтобы предложить понятный способ решения. Еще один важный момент: приоритетность фиксации неполадок: низкая, средняя и высокая – в таблице мы указали, какие проблемы решить нужно прежде всего, чтобы получить улучшение производительности ресурса заказчика.
Последним шагом аудита был обзор архитектуры сайта и связанных с ней систем с целью предложить возможные улучшения. Фишкой нашей работы было то, что таблицу с найденными проблемами мы заполняли постепенно, из-за чего команда заказчика сразу же могла посильно устранять проблемы, а не ждать финальной встречи с демонстрацией результатов.
Примеры проблем и решений производительности, обнаруженных в ходе аудита
Чтобы было понятнее, приведем примеры описания проблем производительности и способов их решения на проекте. Для этого возьмем проблемы, связанные с CSS, API, шрифтами и скриптами, которые использовались в системе
Отсутствие извлечения стилей из компонентов Vue (40 часов на исправление)
На проекте используется фреймворк Vue. Одной из проблем производительности сайта заказчика было то, что стили, расположенные во Vue компонентах, работали неправильно – они грузились с помощью JS и не генерировались самостоятельно, что откладывало их применение до инициализации и скачивания.
Чтобы решить проблему извлечения стилей, было предложение следующее решение:
- Сделать маппинг роутов и чанков в веб-приложении
- Сделать хелпер для Laravel для добавления инлайнового CSS по роуту
Блокирующие API запросы (30 часов на исправление)
Система, над которой мы работали, помогает пользователям находить и бронировать туры, оплачивать поездки и проживание в отелях. Поэтому, для того, чтобы все множество различных данных, необходимых для решения пользовательских задач отображалось корректно, ресурс заказчика использует большое количество API запросов за конфигурацией – это, например, разные валюты и их конвертация, опции настраиваемых пользователем при поиске фильтров. Из-за того, что запросов очень много и они зависят друг от друга, отрисовка контента на сайте замедляется, и пользователю приходится ждать.
API запросы нельзя просто сократить или удалить. Каждый из них несет функцию, которая необходима сервису для корректной работы. Поэтому в таком случае, чтобы ускорить отрисовку контента, объединяем по возможности запросы в один API endpoint, чтобы конфигурации запрашивали не по одной, а сразу по несколько. Другой способ – заинлайнить результат выполнения запросов в html в формате JSON.
Приоритет загрузки шрифтов (6 часов на исправление)
Чтобы контент на сайте отрисовывался быстро, необходимо, чтобы его загрузка была приоритезирована. Например, появление текста в нужном формате на странице не должно отставать от остальных элементов, чтобы не было ситуации, когда один сегмент сайта уже загрузился и активен, а другие до сих пор отображаются в непонятном виде.
Так, в нашем проекте у шрифтов, используемых на страницах сайта не было высокого приоритета загрузки. Из-за чего тест загружался позже, чем это было необходимо для быстрой отрисовки контента. Кроме того, пока шрифты не загружались, текст вообще не отображался на экране.
Чтобы решить эту проблему, нужно было реализовать предзагрузку необходимых страницу шрифтов. Для этого мы использовали метод preload, который позволяет ускорить загрузку страницы, управляя процессом загрузки отдельного элемента – в нашем случае определенного шрифта.
Вот как это выглядело в коде:
Слишком большие JS бандлы (18 часов на исправление)
Код проекта обычно разбивается на бандлы, относительно своей функциональности. Это полезно и с точки зрения удобства разработчиков, и с точки зрения использования ресурсов для загрузки страниц веб-сервиса: когда код разделен на группы, с ним проще работать и человеку, и компьютеру. Однако, когда такие кодовые группы перегружаются, работа с ними усложняется, поэтому важно не закидывать в бандл слишком много кода и следить за тем, чтобы весь код бандла был действительно необходим для работы сервиса.
На нашем проекте проблема чрезмерной величины JS бандлов была связана среди прочего с применением пакета moment. Это библиотека, позволяющая упрощать работу с датами и временем через определенные методы. Это тяжелая и устаревшая библиотека, которую рекомендуют заменять на более легковесные аналоги, например, dayjs.
Другой пакет – Lodash – был добавлен в бандл полностью, хотя в проекте применяется только часть его функциональности. Для оптимизации lodash были заменены импорты библиотеки. import _ from "lodash";заменен на import forEach from "lodash/forEach";. Кроме того, на проекте были использованы несколько версий одной и той же библиотеки Lodash – мы привели все к одной версии, за счет чего сократили в несколько раз объем JS бандлов.
Чтобы решить проблему перегрузки бандлов, мы применили tree-shaking компонентов. Простыми словами – это “стряхивание” неиспользуемого кода при сборке приложения. В дальнейшем нужно будет контролировать импорт элементов в бандлы, не пропуская те, что идут, например, по-умолчанию в пакете, но на самом деле не нужны для реализации фич сервиса.
Также перегружать бандлы могут лишние языковые пакеты. Их можно исключить с помощью ContextReplacementPlugin.
Итоги проекта
4 недели потребовалось на то, чтобы провести установочные встречи с заказчиком , сам аудит и все обсуждения и презентации, связанные с ним.
Среди проблем туристической системы мы выявили 28 кейсов, 10 из которых имели высокий приоритет, 13 – средний и 5 – низкий. Выявили проблемы, связанные с CSS, JS, загрузкой шрифтов и изображений, API, кэша, работы бэкенда и мониторингов. Фронт работ по устранению всех проблем был оценен примерно в 400 часов.
Получилось настроить синергетический режим работы, при котором команда заказчика не просто находилась в ожидании до конца наших работ по аудиту. Как только мы выявляли каждую их проблем и предлагали решение, специалисты из команды заказчика могли оперативно приступать к исправлению проблем производительности.