Разработка
Улучшение производительности Android-приложения NordVPN с помощью плагина Compose Compiler
Эта практика помогает нам использовать плагин Compose Compiler в качестве проверки Composable кода, что поддерживает стандарты кодирования и способствует повышению производительности приложения.
Новая интеграция Compose вызвала множество внутренних обсуждений, касающихся производительности приложения. Одним из направлений нашей работы в NordVPN является интеграция плагина Compose Compiler в ежедневный процесс разработки, что помогает нам улучшить наш код. В этой статье мы объясним, что такое плагин Compose Compiler, как он работает и как мы используем его в NordVPN.
С какими проблемами мы столкнулись?
При работе с Jetpack Compose мы столкнулись с проблемами производительности, связанными со стабильностью композитных функций. Наша основная цель при работе с composable функциями заключалась в том, чтобы сделать их как можно более стабильными, или «пропускаемыми» (skippable) в терминологии Compose. В данном контексте «пропускаемая» означает, что если параметры функции не изменились с момента предыдущей перекомпоновки, Compose пропустит функцию и повторно использует предыдущие значения.
С помощью Compose мы можем увидеть значительное повышение производительности, поскольку даже незначительные улучшения могут снизить количество перекомпозиций во всем приложении. Чтобы оценить стабильность композитных функций, мы можем использовать плагин Compose Compiler.
Плагин Compose Compiler
Compose Compiler — это плагин, который может генерировать отчеты и метрики для компонентов или кода, написанного на Compose. Эти отчеты предоставляют подробную информацию о поведении нашего кода на Compose. Плагин был добавлен в версию 1.2 библиотеки Compose.
Получив такую подробную информацию, мы можем приступить к улучшению нашего кода.
Как это работает?
Плагин Compose Compiler — это задача Gradle, которая генерирует отчеты для композитного кода в модуле. Он оценивает стабильность кода, предлагая гибкость при необходимости запускать его локально или в CI-конвейере.
Рекомендуется генерировать отчет в Release сборках.
Чтобы убедиться, что плагин работает идеально, сначала нужно настроить его в Gradle-файле проекта.
1 tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { 2 compilerOptions { 3 if (project.findProperty("nordvpn-app.enableComposeCompilerReports") == "true") { 4 freeCompilerArgs.addAll([ 5 "-P", 6 "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + 7 project.buildDir.absolutePath + "/compose_metrics" 8 ]) 9 freeCompilerArgs.addAll([ 10 "-P", 11 "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + 12 project.buildDir.absolutePath + "/compose_metrics" 13 ]) 14 } 15 } 16 }
Первая часть кода генерирует отчеты, а вторая — метрики для этих отчетов.
Чтобы запустить этот код, мы используем команду Gradle следующим образом:
./gradlew assembleRelease -Pnordvpn-app.enableComposeCompilerReports=true
По завершении выполнения в папке сборки создается файл, как показано ниже.
Здесь:
- *-classes.txt: содержит информацию о классах, на которые ссылается composable функция.
- *-composables.csv: CSV-версия TXT-файла.
- *-composables.txt: содержит подробный вывод каждой Composable.
- *-module.json: предоставляет подробную статистику в виде комплексного представления.
В нашем случае мы в первую очередь ориентируемся на файлы *-composables.txt и будем работать с ними.
На изображении выше показано сгенерированные файлы только для одного модуля. Однако в NordVPN у нас несколько модулей пользовательского интерфейса, и каждый модуль генерирует свою собственную папку compose_metrics (в которой находится код Compose) со всеми соответствующими отчетами.
Уточнение сгенерированного отчета
Поскольку все наши модули генерируют отчеты, вот пример того, как отдельный файл -composables.txt может содержать несколько блоков кода, например:
1 restartable scheme("[androidx.compose.ui.UiComposable]") fun ScreenContent( 2 stable onBack: Function0<Unit> 3 stable onSettingToggled: Function0<Unit> 4 unstable state: State? 5 stable modifier: Modifier? = @static Companion 6 }
Каждый из этих файлов содержит множество функций, которые демонстрируют структуру кода в стиле Kotlin. Кроме того, каждый модуль с кодом Compose имеет отдельный текстовый файл. Прежде чем вдаваться в подробности, давайте рассмотрим значения в этом коде:
- Restartable: Когда Compose обнаруживает изменения во входных данных функции, он перезапускает функцию, вызывая ее снова с обновленными входными данными.
- Stable: Этот параметр в предоставленной функции является стабильным. Если он не изменился, Compose пропустит его.
- Unstable: Этот параметр в предоставленной функции нестабилен, и Compose всегда перекомпонует его, когда перекомпонуется родитель.
Затем мы объединяем все файлы *-composables.txt в один текстовый файл в рамках нашего проекта с помощью скрипта, который мы создали для этой цели. Этот объединенный файл играет важную роль в нашем процессе разработки. Давайте посмотрим, как мы его используем.
Как мы используем его в повседневной разработке?
В NordVPN мы легко интегрировали этот рабочий процесс в наш CI-конвейер для каждого создаваемого нами pull request, гарантируя, что мы сливаем только стабильный код Compose (когда это возможно) в наши основные ветки.
Однако перед внедрением этого процесса мы проводим тщательную проверку, чтобы убедиться, что весь наш код Composable не содержит лишних нестабильных параметров. Этот проактивный шаг гарантирует, что когда мы внедряем этот процесс в наш поток пул-реквестов, мы начинаем его с чистого листа.
Давайте подробнее рассмотрим этапы работы над pull request:
- Создание пул-реквеста: Процесс начинается с создания запроса (PR).
- Задача CI: CI-джоб запускается для текущего PR в случае изменения любого из модулей пользовательского интерфейса. Задание CI выполняет несколько задач:
- Генерация отчета: Мы генерируем отчет для релизной ветки, что приводит к созданию нескольких текстовых файлов в каждом модуле, содержащем код Compose.
- Слияние текстовых файлов: На этом этапе мы выполняем скрипт, который объединяет эти текстовые файлы, сохраняя только функции, содержащие нестабильные параметры.
- Создание таблицы в формате markdown: Далее мы создаем таблицу в формате markdown, в которой перечислены имена функций и связанные с ними нестабильные параметры.
- Публикация комментария: Мы публикуем эту таблицу в виде комментария в PR. Это информирует разработчиков о любых потенциальных нестабильностях, внесенных в PR.
- Исправление: Если проблемы нестабильности выявлены, мы исправляем затронутые функции и фиксируем изменения.
Затем весь процесс повторяется, и если проблемы с нестабильными параметрами были устранены, дальнейшие комментарии не публикуются. Все предыдущие комментарии по этому вопросу уже решены.
Эта практика помогает нам использовать плагин Compose Compiler в качестве проверки Composable кода, что поддерживает стандарты кодирования и способствует повышению производительности приложения NordVPN для Android.