При выборе технологий зачастую всплывает такой аргумент, как долгая сборка из-за генерации кода. При этом редко кто оперирует точными цифрами. Давайте на примере мобильного приложения Yota разберёмся, чего нам стоит генерация кода через kapt.
Спойлер. Я был шокирован цифрами.
Немного о проекте Yota:
- библиотеки, которые используют kapt: Dagger, Room, Glide;
- количество модулей на момент написания статьи: 157;
- количество кода: примерно 400k.
Первым делом определимся с тем, как будем замерять.
Нам необходимо запустить сборку максимально на холодную, чтобы отработали все задачи без исключения. Для этого есть настройка -rerun-tasks. Также выключаем кэширование задач: --no-build-cache. И перед всем этим почистим текущий кеш командной clean.
В итоге получаем последовательность команд:
./gradlew clean
./gradlew :app:assemble{Flavors}Debug --rerun-tasks --no-build-cache --scan
- :app – название вашего application модуля;
- assemble{Flavors}Debug – gradle таска по сбору приложения. Flavors: ваши build flavors. Могут отсутствовать. Обычно это prod или dev;
- scan запускает сканирование нашей таски.
Когда таска закончится, необходимо согласится с политикой приватности и пройти несложный процесс активации скана. Подробнее здесь.
После активации переходим на вкладку timelines и смотрим, что получилось:
Здесь мы можем увидеть: как сильно распараллелена сборка нашего проекта и сколько составляет её общее время (8m 41.420s).
Теперь посмотрим, сколько всего времени занимали таски на всех потоках. Для этого в поиск вводим “:”, что эквивалентно любой задаче.
Итого на все таски потрачено 39m 47.615s.
Теперь из этого необходимо получить время kapt задач. Аналогично, ищем по ключевому слову “kapt”:
Kapt задачи заняли 18m 1.642s.
И настало время расчётов.
Итого в нашем проекте kapt — это 45,3% сборки.
Есть ещё одна интересная опция для измерения — отфильтровать задачи по критическому пути.
Критический путь задачи — это самая длинная по времени выполнения цепочка зависимых задач. Это оценка кратчайшего возможного времени сборки при условии, что доступны бесконечные вычислительные ресурсы и все независимые задачи могут выполняться параллельно.
Таким путём получаем результат в 6 m 16.506s.
Следующим шагом выделяем из них kapt задачи:
На kapt задачи ушло 2m 35.247s.
По аналогии с предыдущим методом считаем финальный показатель:
По итогу обоих расчётов получили примерно одинаковые значения.
Разбирая результаты, стоит отметить, что основную долю kapt у нас занимает Dagger, где-то 98%. Он присутствует в 90 модулях из 157.
На этом моменте должны заликовать сторонники runtime DI фреймворков. Однако при таком количестве модулей уже не обойтись без статической проверки дерева зависимостей.
Вместо заключения
Не будем делать дополнительных выводов, цифры говорят за себя. Отмечу только, что теперь становится понятнее, почему все так ждут KSP (Kotlin Symbol Processing), который обещает уменьшить время генерации кода на половину. В нашем проекте это почти четверть времени сборки, почти бесплатно. Учитывая долю kapt Dagger ждём самое главное его.
Делитесь в комментариях: какой процент времени занимает kapt в вашей сборке?