Меня зовут Дима, я iOS инженер-менеджер в крупнейшем телеком-операторе Казахстана. У нас 19 разработчиков — и билд-тайм для нас важная составляющая разработки. В этой статье я пройдусь по следующему пути: 

  • рассмотрю стратегии, которые вы сможете сразу применить; 

  • покажу реальные цифры из наших проектов; 

  • сделаю выводы и поделюсь инсайтами. 

Проблема

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

Разработчики часто игнорируют билд-тайм, пока он не превращается в проблему. Возможно, поставить утром сборку на 30 минут и пойти пить кофе — это круто, но я считаю, это неэффективно. Если представить человека, который постоянно пытается ускорить билд-тайм, то вот он: руки у него в копоти, потому что он по 50 раз запускал билд-тайм, и руки его горят. 

Три кита оптимизации 

По известной пирамиде тестирования мы прекрасно понимаем, что больше всего у нас будет unit-тестов, интеграционных тестов, и меньше всего — UI-тестов, потому что они дороже. Эта статья будет построена на трёх китах с картинки. 

Изображение выглядит как текст, снимок экрана, Шрифт, линия  Контент, сгенерированный ИИ, может содержать ошибки.

Вертикальное скалирование

Начнём с вертикального скалирования самый доступный и дешёвый способ ускорения билда — обновление оборудования. Например, переход с MacBook 2018 года на базовую модель MacBook Pro с процессором M1 позволил сократить билд-тайм с 348 до 136 секунд. Всю историю этих изменений можно найти в репозитории XcodeBenchmark. 

Изображение выглядит как текст, снимок экрана, Шрифт, дизайн  Контент, сгенерированный ИИ, может содержать ошибки.

Оптимизация проекта 

Тут давайте сначала о другом: прежде чем начинать ускорение билд-тайма, вам нужны цифры. Цифры, которые можно будет показать команде как доказательство проблемы. Итак, профилирование. 

Профилирование помогает замерять текущие показатели сборки и находить узкие места. В Xcode для этого есть инструмент Build with Timing Analysis, который показывает: 

  • Время сборки каждого модуля. 

  • Зависимости, которые замедляют процесс. 

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

В одном нашем проекте долгое время занимала компиляция ассетов из-за одной некорректной картинки. После её замены проблема была решена. 

Теперь непосредственно к оптимизации проекта. Этого кита я делю ещё на три: конфигурация, исходники и зависимости. 

Конфигурация проекта 

Хоть Apple и cтарается делать комфортно для всех, у проектов есть всё-таки своя специфика. Например, часто ребята не понимают разницу между дебаг и релизной сборкой: в дебаг-сборке можно отключить неиспользуемые архитектуры и оптимизации, которые вам не нужно тащить при каждом билде. 

Изображение выглядит как те��ст, снимок экрана, Шрифт  Контент, сгенерированный ИИ, может содержать ошибки.

Также вы можете настраивать Optimization Level, когда вам не нужно каждый день улетать в App Store. 

Изображение выглядит как текст, снимок экрана, Шрифт, число  Контент, сгенерированный ИИ, может содержать ошибки.

И таких настроек у Apple достаточно много: 

  • Link Time Optimization 

  • Precompile Prefix Header 

  • Swift Compiler Optimization Level 

  • Eager Link 

  • Parallel Build Tasks 

  • Clean Derived Data 

Особенно Clean Derived Data — любимый пункт у айосеров. Помню, было модно отдельно запрограммировать кнопку на тачбаре под эту настройку — и чистить её через день, потому что она ломала всё, что есть. Но сделана она всё равно круто. 

Настройки

Теперь стоит проверить две главные настройки для ускорения билда — Increment build и Parallel build. Инкрементная сборка позволяет повторным билдам обрабатывать только изменённые файлы. А для параллельной сборки Apple каждый год старается выжимать максимум из своего железа — и после такой многозадачности вы будете экономить всё больше времени. 

И напоследок, не забудьте проверять Script phases. Бывает, приходит новенький, затаскивает новый скрипт, который ускоряет работу, а используется раз в месяц. А наш билд-тайм увеличивается на 20 секунд. 

А если хотите ещё больше инфы, WWDC — это та самая крутая конференция, которая проходит каждый год. Помимо презентации новых айфонов и макбуков, Apple уделяет внимание ускорению билд-тайма. Вот несколько моих любимых материалов: 

Исходный код  

Второй кит — это то, что мы пишем каждый день. Немного цифр: 

  • 3 приложения (2 основных, 1 внутренний продукт), 

  • 200+ тысяч строк кода, 

  • 20+ внутренних модулей, 

  • 50+ внешних зависимостей. 

Что делать с кодом? Не писать? За это нам не заплатят :-) Но зато есть «мёртвый» код — код, который не используется, но всё ещё существует в проекте. Мы активно его удаляем, чтобы повысить наш coverage. Зачем покрывать то, что не используется? 

Есть такой инструмент Periferry — он показывает при билде, какой код реально используется, а какой нет. Благодаря нему мы удалили 25 000 строк, а это 10% кодовой базы. 

Если разработчики не хотят удалять свою мертвую прелесть, отлично — предложите им положить прелесть в Swift Packages. 

А ещё лучше — сделать из неё бинарный файл. Такой код будет скомпилирован, и что бы вы ни меняли, это не будет влиять на билд-тайм. Вы можете кэшировать файл, например, локально на своем макбуке или на сервере для коллег.  

Зависимости

В своих проектах мы используем SPM (Swift Package Manager) — он позволил нам ускорить работу с зависимостями. 

Но у SPM есть свои проблемы: у нас тоже бывают баги, крашимся, всё что угодно. Например, одна из библиотек после клонирования занимала 786 МБ. Посмотрели исходники в Github — 200 Кб, посмотрели Binary Library — 12 МБ. 

786–12=774!!! — что-то математика не сходится. 

По сути, SPM клонирует всю репу. Там есть исходный код, есть картинки, есть что-то другое… а есть история! Тут-то вся и проблема. Если вы закидываете бинарные файлы в гит, он их не заменяет, он их хранит — всю свою жизнь. Поэтому, когда вы будете стягивать SPM, посмотрите, откуда тянутся ваши бинарные файлы. 

Оптимизация билд-системы 

Третий кит — это попробовать изменить способ работы с билдом. Проект — это тяжелая вещь, где мы должны организовать тысячи файлов, сотни зависимостей. У себя мы используем Tuist. Конечно, есть свои плюсы и минусы, и мы понимаем, куда можно расти. 

Цифры после всех оптимизаций и Tuist 

Замеряли мы на Macbook Pro 14 M2, а проектом выбрали приложение Altel. Билд-тайм с SPM на холодную без стягивания зависимостей занимал 130 секунд, вроде не так страшно.  

Если ускорить с Tuist без бинарного кэша — выходит 70–85 секунд. Всё потому, что Tuist умеет оптимизировать зависимости — делать из неявных явные. 

Если ещё кэшировать внешние пакеты — выходит 33 секунды. Цифры, конечно, могут меняться от тех или иных условий. 

Но я как-то подумал:, «Ччто, если закэшировать все наши библиотеки?» — получилось 20 секунд. Ускорение в 6 раз.! 

А вот и пруфы. Слева можно у��идеть, насколько изменилось время, которое тратилось на анализ зависимости — он занимает меньше 5 секунд. Справа — как билдится исходный код проекта. Конечно, мы тратим время на построение кэша, но не всё же в этом мире — бесплатно. :-)  

Пару слов под конец  

Мой личный посыл в этой статье — не бойтесь экспериментировать. Когда долго сидишь в комфорте, начинается стагнация. Будьте вечным студентом, который зайдет и сломает всем проект в Xcode, запушит это в гит. Кто-нибудь его скачает, спросит: «Кто сломал проект %:№()#???», и ты такой смотришь: «А это мой коммит :-)». И всё! 

Редактор: Ефрат Гараев