Привет, меня зовут Михаил Юдин, я Android-инженер в Авито. Хочу рассказать, в чём польза перформанса и как начать внедрять его в продукте. Осенью 2018 года у нас появилась команда перформанса — есть шаги и инструменты, которые нам помогли, поэтому пора делиться опытом.
Что такое перформанс
Мы поговорим про Perceived performance. На русском это что-то вроде воспринимаемой производительности — то, насколько быстрым ваш продукт кажется пользователю. Это важная часть пользовательского опыта. Возможно, даже более важная, чем реальная производительность.
Инструменты перформанса нужны, когда на сайте заметно, как подгружаются веб-шрифты или долго крутится колесико лоадера вместе картинки. Чтобы понять, долго — это сколько, есть общепринятые значения. Например, отклик за 100—300 миллисекунд мы воспринимаем как мгновенный. Это из-за свойств человеческого мозга — чтобы свести все сигналы внешнего мира в одну картинку, мозг сам задерживает отклик до 80 миллисекунд. Для нас эта разница незаметна.
Работа с перформансом помогает не терять пользователей. Например, человек заходит в приложение и какое-то время ждёт, пока запрос отправляется на бэкенд и возвращается обратно. Если в это время мы показываем ему пустой экран, пользователь взбесится и уйдет. Подумает, что приложение сломалось, или просто не захочет ждать. Но стоит добавить лоадер или вывести полезные сообщения — пользователь останется с нами.
Есть фрагменты приложения или сайта, которые нельзя сделать быстрее. Но вы можете создать у пользователя ощущение, что процесс занимает меньше времени, чем на самом деле. Лоадер или анимация перехода сами по себе не влияют на результат — это лишняя работа, которую совершает приложение. Но эти инструменты как бы дают пользователю обратную связь, сообщают, что всё работает и вот-вот загрузится.
Нет волшебной метрики, которая поможет проверить чувства и ощущения пользователя. Но по некоторым показателям мы можем увидеть, где возникают проблемы из-за недостаточно хорошего перформанса.
Как это работает
Перформанс влияет на все продуктовые метрики и SEO-трафик. Медленные страницы раздражают пользователей и хуже ранжируются в поисковиках. Поэтому нужно сделать так, чтобы медленное казалось быстрее. Если запрос занимает много времени, есть способы создать впечатление быстрой загрузки. Например, скелетон, лоадер, различная анимация экрана.
Эксперименты хорошо показывают, как перформанс влияет на продуктовые метрики. Мы замедлили в веб-версии Авито несколько экранов, поисковую выдачу, открытие карточек. Через две недели метрики показали, что целевые действия снизились. Замедление на две, четыре и шесть секунд привело к тому, что пользователи реже кликали на рекламу, смотрели меньше объявлений.
Надо учитывать контекст — это приложение для оказания первой медпомощи или онлайн-кинотеатр? Пользователь мёрзнет на остановке или лениво перебирает товары, лежа на диване? В разных ситуациях может быть разная готовность ждать. А ещё люди слишком разные, поэтому нет универсальной формулы, которая покажет вам идеальное время для задержки отклика.
Сервис может быть слишком быстрым. И это тоже надо учитывать, когда хочешь ускорить что-нибудь. Например, пять секунд подождать, пока рендерится сложная модель здания — это нормально. А за пять секунд получить заказ в ресторане — так себе ситуация. Такая скорость подозрительна: может, они готовят еду заранее или подают блюдо, от которого кто-то только что отказался? Нужно думать об ожиданиях пользователя.
Есть ситуации, когда не до перформанса. Например, у вас стартап, и главная задача — реализовать функциональность. Тогда работа с перформансом будет не в приоритете. Но если вы пишете приложение с единственной функцией, она должна работать идеально. Здесь такой инструмент может помочь.
Ускорение бэкенда
В Авито микросервисная архитектура. Это значит, что при каждом обращении на бэкенд, у нас разворачивается множество микросервисов. Поэтому мы применяли инструменты, которые лучше всего находят слабые места в такой структуре:
- Opentracing (Jaeger). Это технология, которая позволяет отправлять request ID и составлять карту, на каком этапе что поломалось.
- The Four Golden Signals: Latency, traffic, error, saturation. Это даже не инструмент, а глава из книги. Суть в том, что вы следите за ошибками, памятью, ресурсами. И когда вы делаете это, повышается качество перформанса.
Классические ошибки бэкенда, которые мы исправили через перформанс:
- Выносить необязательные элементы в отдельный запрос. Обычно всё устроено так: пользователь отправляет с экрана запрос, а мы собираем всё на бэкенде и возвращаем ему. Из-за того, что все данные собираются и отправляются одним потоком, ответ приходит, допустим, через полторы секунды. Это долго, пользователь вне себя. Поэтому мы разделяем запрос. Например, подгружаем рекламу отдельно от остального контента.
- Не запрашивать в цикле данные у базы. При внедрении цикла легко забыть про транзакцию. Если исправить такие ошибки, сэкономим ещё немного времени на отклик.
- Распараллеливать запросы. Часто запросы идут не параллельно, а суммируются. Если их разделить, уменьшится общее время запроса. Здесь нужно учесть возможности языка. Например, в PHP такая опция зависит от версии.
- Не запрашивать лишние данные. Это приходится проверять вручную. Но отказ от лишних запросов тоже даёт хорошее ускорение.
- Переиспользовать данные. Если ваше приложение бесполезно офлайн, то не используйте базу. Например, в приложении Авито не получится запросить телефон продавца, если нет подключения. База в этом случае добавляет задержки. Поэтому мы решили складывать такие данные в отдельный фрагмент, который доступен только при активном приложении.
- Time to content. Чтобы ускорить загрузку контента, можно проверить необходимость инициализации библиотек, классов в мейн-треде. А ещё просто убрать с мейн-треда или назначить ленивую загрузку для всего, что кажется лишним.
- Дебаунсы. Это искусственно добавленная задержка отклика. Такое нужно, чтобы скрыть процессы загрузки, показав только результат. Если убрать дебаунсы, мы получим ускорение без лишних усилий.
Многое можно ускорить дёшево и без серьёзных вложений времени. Эти изменения лежат в условной «зеленой зоне» на кривой ускорения Шипилёва. Здесь сосредоточен самый большой объём возможных действий по ускорению. Всё, что в красной и жёлтой зонах требует значительных усилий и показывает не такой ощутимый результат.
Типичные ошибки фронтенда, которые мы исправили
Фронтенд сложнее для наблюдений, чем мобильное приложение. Обновления в приложении выкатывают раз в две недели, а на фронтенде что-то новое появляется несколько раз в день. Здесь больше пространства для изменений, которые могут снижать перформанс. Чтобы их вовремя замечать, мы пользовались этими инструментами:
- Google Lighthouse. Это инструмент, который позволяет профилировать. Его можно встраивать в CI/CD.
- Overlooker. Решение, аналогичное Lighthouse, но со своими преимуществами. Например, этот инструмент умеет предзаписывать сеть. Так вы получаете точные метрики, когда делаете перформанс-тесты на сайте. Еще Оверлукер показывает ретроспективные метрики.
Вот с какими ошибками помогают справиться эти инструменты:
- Дублирование кода зависимостей. Из-за расхождения версий в разных внутренних пакетах могут дублироваться фрагменты кода.
- Неиспользуемые CSS. Скрипты, которые блокируют загрузку страницы и утяжеляют рендер. Их удобно отслеживать и блокировать.
- Тяжёлый рендер. Чтобы ускорить, нужно выделять асинхронные блоки. И быть осторожнее с тяжёлыми шрифтами.
Используйте перформанс-модель, чтобы увидеть слабые места продукта — и на фронтенде, и на бэкенде. Определите блоки, с которыми работаете и добавляйте Service Level Agreement. Например, мы видим, как загружается карточка объявления. На первом уровне — сама загрузка, подготовка и показ карточки. На втором — то же для похожих объявлений, рекомендаций. Третий уровень работает с рекламой. Мы замерили все уровни и добавили SLA. Затем задали для загрузки значения, ниже которых быть не должно. Теперь понятно, какие блоки можно ускорять и как их переставлять.
Как это внедрять
Мониторинг и перформанс-тесты. Настройте мониторинги метрик, а затем выстраивайте систему. А ещё полезно сесть командой и подумать, какую культуру перформанса вам хочется получить. Например, разработчик хочет проверить идею — внедрить какое-то изменение, провести тесты, сравнить метрики. Он может рассчитывать, что его поддержат остальные? Команда поделится опытом, даст всё необходимое для работы?
Мониторинги — это реактивный подход. Когда мы провели исследование, увидели проблему и отреагировали. А перформанс-тесты — проактивная стратегия. С ними мы проверяем, как решения влияют на перформанс. Если видим ухудшение, то не внедряем такое решение. Например, в Авито мы собираем две версии приложения — с изменениями, которые хотим внедрить, и действующую версию. На обеих прогоняем перформанс-тесты и сравниваем результаты.
Замедлите что-нибудь. Вы увидите нелинейную зависимость — медленные куски дают худшие метрики.
Посмотрите, что там у конкурентов. Нет смысла бросать все силы на секундное ускорение. Иногда нужно делать функциональность, а иногда — перформанс. Разберитесь, что для вас сейчас важно.
Проверьте самые медленные места — возможно, нужно почистить код, и этого будет достаточно. Например, мы обнаружили в коде остатки теста, который давно сняли. Каждый раз он давал замедление, хотя мы уже не снимаем эти данные. Убрали — получили ускорение.
«Рассинхронизируйте» загрузку данных. Правильно расставьте приоритеты. Если нужно показать 30 карточек товаров с названием и ценой, дайте вначале хотя бы текст.
Проводите тесты и мониторинги, смотрите на метрики. Если нужно, идите с этими цифрами к руководителю. Например, на карточке в приложении Авито есть лишняя секунда, а карточка отрисовывается 150 млн раз в день на четырёх платформах. За год получаем 1736 лет дополнительного ожидания. Если учесть, что средняя продолжительность жизни в России 73,7 года, то одна лишняя секунда на карточке превращается в 23,5 человеческих жизни за год. А Амазон подсчитал, что каждая лишняя секунда в год для них это 1,6 млрд долларов, которые можно было бы заработать. Эти подсчёты убеждают лучше, чем разговоры о гипотетической пользе перформанса для продукта.
Соберите единомышленников. Это бэкендеры, фронтендеры, мобильные разработчики. Хорошо, когда в команде перформанса есть product owner. Этот человек знает, что происходит в компании и чем занимаются другие команды. А еще он глобально смотрит на цели вашей команды, потому что хорошо знает продукт. Это помогает фокусироваться на главном.
Обучайте команду. Пусть разработчик пишет код сразу с учётом перформанс-стратегии. Это не столько про скорость, сколько про восприятие. Поэтому общайтесь еще и с дизайнерами.
Говорите с разработчиками и менеджерами про перформанс. Это важно, потому что так создается культура перформанса. Если внедрять перформанс сверху или начинать работу с ним без понимания пользы и целей — идея обречена на провал. Начните со сплит-тестов, покажите результаты. Проще заботиться о перформансе и продвигать его, когда у вас есть реальные цифры, понятные менеджеру.