Site icon AppTractor

Производительность мобильных приложений, ориентированная на пользователей

Привет, это Пьер-Ив Рико, в течение последних трех лет я рулил вниманием Square в области мобильной производительность и создавал фреймворк для ее осмысления и определения приоритетов в работе. В этой статье я рассказываю о своем подходе.

Полезные метрики

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

Говоря о производительности, важно быть точным и обозначать ее объективными критериями, которые можно измерить количественно. Эти критерии называются метриками.

Но если метрика основана на объективных критериях и может быть измерена количественно, это еще не значит, что такое измерение полезно.

Источник: web.dev

Полезны для чего? Команды разработчиков продуктов имеют дело с конкурирующими приоритетами, и им нужен сигнал, чтобы знать, когда и где нужно расставить приоритеты в работе над производительностью, т.е. они должны знать, когда низкая производительность влияет на опыт клиентов и, в конечном счете, снижает бизнес-показатели.

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

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

Например, при экспорте видеоролика Insta360 я, как пользователь, хочу, чтобы приложение максимально использовало GPU и CPU, чтобы экспорт проходил быстрее.

Insta360 (выделено фиолетовым цветом) использует все потоки CPU при экспорте видео.

Показатели эффективности, ориентированные на пользователя

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

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

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

Существует две широкие категории показателей производительности, ориентированных на пользователя:

Пороговые значения, основанные на человеческом факторе

Исследования пользовательского опыта показывают, что люди не воспринимают улучшения задержки, превышающие определенные пороговые значения: 11 мс для задержки движения перетаскивания на экране (плавность) и 69 мс для задержки взаимодействия с экраном (отзывчивость).

В документации Apple по отзывчивости приложений проводится аналогичное различие:

Приложение, которое мгновенно реагирует на действия пользователя, создает впечатление, что оно поддерживает его рабочий процесс. Если приложение реагирует на жесты и касания в реальном времени, у пользователей создается впечатление, что они непосредственно манипулируют объектами на экране. Приложения с заметной задержкой при взаимодействии с пользователем (зависание) или движениями на экране, которые кажутся скачкообразными (заминка), разрушают эту иллюзию. В результате пользователь начинает сомневаться, правильно ли работает приложение. Чтобы избежать зависаний и заминок, при разработке и тестировании приложения придерживайтесь следующих приблизительных пороговых значений.

Плавность

Любой вид движения на экране требует синхронизации обновления кадров с частотой обновления дисплея, иначе человек заметит дрожание (джанк).

Движение на экране может быть интерактивным и неинтерактивным. Интерактивное — это когда палец касается дисплея, а пользовательский интерфейс следует за ним, т.е. перетаскивание (медленная прокрутка списка или drag & drop). Неинтерактивными могут быть анимация или прокрутка на основе взмаха руки.

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

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

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

Отзывчивость

Метрика отзывчивости — это любая метрика, которая отслеживает задержку между действием пользователя и видимым ответом системы, т.е. взаимодействием. Вот несколько примеров:

Пороговые значения отзывчивости

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

Эти разные ожидания обусловлены нашей способностью к формированию шаблонов. Люди очень хорошо умеют улавливать тенденции и определять отклонения. Если большинство приложений запускается за 2 секунды, то пользователи сразу же замечают приложения, которые запускаются за 500 мс или 5 секунд.

Это означает, что мы можем иметь два порога отзывчивости для каждой метрики:

Эти пороги не могут быть универсальными, они зависят от конкретного контекста (low-end и high-end устройства, какие еще приложения используются пользователями и т.д.).

Аналогичный подход можно найти в документации Interaction to Next Paint (INP), где два порога длительности (200 и 500 мс) определяют оценку GOOD/NEEDS IMPROVEMENT/POOR для каждого измеренного образца.

Я использовал аналогичные пороговые значения в Square, но не был уверен в том, что смогу превратить их в единый показатель производительности, поэтому в основном ориентировался на P90.

Тай Смит только что указал мне на показатель Apdex, который также определяет два пороговых значения для разделения образцов на три группы (удовлетворительные, терпимые, разочаровывающие), а затем выдает оценку как средневзвешенное значение количества.

Критические показатели

Время запуска приложения имеет решающее значение, если клиенты используют приложение в течение короткого времени. Время запуска приложения менее критично, если клиент намерен использовать приложение постоянно в течение длительного времени (например, приложение для водителей Lyft, приложение для точек продаж, приложение для регистрации посетителей и т.д.).

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

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

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

Предвзятость в агрегированных данных

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

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

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

Правильный учет этих показателей затруднен

Как Google, так и Apple не смогли предоставить полезные API для наблюдения за производительностью, которые позволили бы разработчикам приложений легко отслеживать показатели производительности, ориентированные на пользователя.

Вендоры наблюдаемости предоставляют SDK, которые отслеживают эти показатели, но проблема в том, что все они делают это ужасно. Серьезно.

Пример 1: запуск приложения

Руководства и инструментарий для измерения времени запуска приложений на Android отсутствуют и непоследовательны, давайте разберемся в деталях.

Play Store Android Vitals

Показатели Play Store предоставляют выборочные и анонимные сводные данные о холодных, теплых и горячих запусках.

Play Store считывает данные из внутреннего лог-трекера (не logcat), в который пишет процесс system_server. Сообщаемое время запуска совпадает с тем, что записывает в logcat ActivityTaskManager при запуске:

I/ActivityTaskManager: Displayed com.example.logstartup/.MainActivity: +1s185ms

Я исследовал записанные значения в статье “Как adb измеряет запуск приложений” . В результате этого исследования выяснилось, что:

Макробенчмарк Jetpack

Macrobenchmark получает данные о времени запуска из Perfetto, который вычисляет их на основе логов atrace. Например, конструктор ActivityMetricsLogger.LaunchingState запускает трассировку:

        LaunchingState() {
            if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                return;
            }
            // Use an id because the launching app is not yet known before resolving intent.
            sTraceSeqId++;
            mTraceName = "launchingActivity#" + sTraceSeqId;
            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
        }

Затем трассировка подтягивается Perfetto.

В итоге Jetpack Macrobenchmark, Perfetto, Play Store Android Vitals и logcat выдают практически одно и то же значение (трассировка Perfetto запускается с небольшим смещением). Это замечательно, хотя и должно быть более системно задокументировано.

К сожалению, измерение времени запуска приложения в приложении для составления продуктовых аналитических отчетов — это совсем другая история.

Продуктовая аналитика

В большинстве реализаций холодный запуск приложения фиксируется путем измерения:

Оба измерения начала и конца некорректны, однако именно так поступает Firebase Analytics:

Такой подход неверен по нескольким причинам:

Пример 2: задержка взаимодействия с тапом

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

showAboutScreenButton.setOnClickListener {
  val span = tracer.buildSpan("showAboutScreen").start()

  findNavController().navigate(R.id.about_screen)

  span.finish()
}

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

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

Лучший способ?

Вот что нам нужно от Google для запуска приложения:

Перспективы

Моя долгосрочная цель, связанная с этими статьями и библиотекой square/papa, заключается в том, что либо Apple и Google сделают шаг вперед и предоставят сильное руководство и более полезные API для наблюдаемости (например, JankStats), либо мы объединимся как сообщество и создадим надежные SDK с открытым исходным кодом для измерений.

Источник

Exit mobile version