- PVSM.RU - https://www.pvsm.ru -
Команда должна фокусироваться на создании прекрасных и успешных игр, для всего остального есть CI.
Где мы применяем CI? Какие подходы и концепции используем? Зачем собирать и тестировать билды? Развернутый рассказ о CI и о том, как он устроен в Playrix, потянет на курс лекций. Под катом — краткая выжимка и немного акцентов.
Привет.
Для начала небольшая разминка: что такое Continuous Integration? Если команда использует репозиторий и собирает ночные билды — это уже CI? А в чем отличие Continuous Deployment от Delivery? Это почти неважно. Детали — для узкого круга специалистов. Если вы хотите вовлечь в какой-то процесс всю компанию, придумайте ему простое и хорошее название. В Playrix все эти подходы мы называем CI. Это такой локальный бренд и клевый логотип:
CI — это не цель, это инструмент. Должна быть цель, которую хочется достигнуть с помощью Continuous Integration, проблема, которую требуется решить. Бывает, что процессы разработки и релизов в команде построены по принципу «помолились и в продакшн». Иногда это оправдано, но нечасто.
Мы сформулировали для себя цель так: минимизировать вероятность появления интеграционных проблем, минимизировать ресурсы, требуемые для исправления найденных ошибок, сократить время команд разработки проектов на поддержку и сопровождение процессов CI.
CI — это автоматизация процессов сборки билдов, тестирования кода и его доставки в различные окружения, автоматизация рутинных процессов разработки, взаимная интеграция сервисов, которыми мы все пользуемся.
Идея — в системе, которая все автомагически собирает, делает это часто, тестирует и доставляет билд, а еще точечно таргетирует удобный репорт, если что-то пошло не так.
То есть везде или почти везде.
Сборка и тестирование контейнеров, автоматический деплой в Test, Staging и Prod, Rolling и Canary updates — это все у нас есть и больше применимо для сервисов и веб-приложений. Сегодня мы сконцентрируемся на CI для игр: сборке билдов, их тестировании и доставке.
Чтобы достичь сформулированных выше целей, нужно решить несколько задач. Ниже — план, по которому мы идем, когда автоматизируем какой-то процесс в разработке, например, сборку клиента мобильной игры. Это очень удобно — иметь список вопросов, ответив на которые, можно решить любую задачу, которая попадает в команду CI.
Инструкция по сборке билда — это документация, описание нашего автоматизированного процесса. Часто такая документация находится в голове у программистов. Если в команде есть суперспециалист по сборке билдов и без него быстро и без ошибок билд никто больше собрать не может — пора что-то менять, сабмита не будет.
Хорошо, если такая документация оформлена в виде скрипта: ввел командную строку и набор параметров на машине с подготовленным окружением — получил билд.
Лучшая документация процесса — это кот код. Даже если вам зачем-то нужно повторить операцию вручную, вы всегда сможете это сделать, глядя в него.
Журнал билдов позволяет всегда точно сказать: кто, когда, из какого коммита и с каким результатом собрал тот или иной билд. Вчера билд собирался, а сегодня — нет. Смотрим в журнал, находим первый сфейленный билд, видим список коммитов, которые туда попали, — профит.
Журнал еще больше полезен, когда речь идет, например, о серверном коде. Если нет сведений о том, кто и когда обновлял прод, то в общем случае неизвестно, какой именно код сейчас у вас там трудится. А иногда это бывает очень важно, очень.
Можно вести такой журнал в гроссбухе, лучше в таблице или wiki. Список билдов в системе CI — бесценно.
Когда речь идет о сборке билда и деплое в какое-то окружение, обязательно появляется вопрос: а где хранить логины/пароли доступов? Их обычно нужно много: к репозиторию, чтобы скачать исходные данные, к файловому хранилищу, чтобы залить игровые ресурсы, к HockeyApp, чтобы отправить символы, к серверу, чтобы обновить код, и т.п.
Бывает, что все нужные доступы хранятся в репозитории. Есть гипотеза о том, что это не очень хорошо. Часто можно увидеть поле «введите пароль», скажем, в Jenkins, куда автор билда вводит сокровенные символы.
Помнить все пароли наизусть — хороший навык. Наш CI-сервер сам получает необходимые доступы в зависимости от сборки. Обычно — это короткоживущие токены, которые генерируются при старте билда и дают минимальные права ровно туда, куда мы что-то деплоим или откуда что-то читаем.
Централизованное управление сборкой и деплоем позволяет решить задачу разграничения прав доступа к инфраструктуре. Зачем давать кому-то доступ к серверу, если можно дать только доступ к сборке соответствующего билда, который делает нужную операцию на этом сервере? А раз есть билд, значит у нас есть документация и журналирование, ну вы поняли.
Во время сборки билда обычно остается много следов. Нет, не так: во время сборки билда необходимо оставлять как можно больше следов. В репозитории, в таск-трекере, в системе раздачи билдов. Везде, где бы вы ни встретили билд, должны быть следы, которые приведут вас к полной информации о нем.
Эти следы не нужно заметать, наоборот, их нужно аккуратно оставлять и бережно сохранять. Дальше я расскажу об этом подробнее, но сначала нам нужно собрать наш билд. Поехали.
Повторюсь, идея заключается в системе, которая все собирает, тестирует и репортит. Но зачем собирать билд, если его можно не собирать?
У всех разработчиков наших игр установлены pre-commit хуки, т.е. набор проверок, которые выполняются при попытке что-то закоммитить. Проверки запускаются только для измененных файлов, но мы реализовали весьма хитрую систему поиска кросс-зависимостей, чтобы проверить весь связанный контент тоже. Т.е. если художник добавил текстуру, то хуки проверят, что ее не забыли прописать везде, где нужно, и ни разу не опечатались.
Оказывается, хуки ловят значительную часть мелких ошибок. Они экономят ресурсы билд-системы и помогают разработчику быстро исправить проблему: он видит сообщение, где подробно сказано, что пошло не так. А еще ему не нужно переключаться между задачами: он буквально только что вносил изменения и находится в контексте. Время исправления ошибки — минимально.
Нам это настолько понравилось, что мы даже сделали систему, которая проверяет, были ли выполнены хуки для коммита, попавшего в репозиторий. Если нет — автор такого коммита автоматически получит задачу с просьбой их настроить и подробной инструкцией, как это сделать.
Хуки унифицированы для всех проектов. Количество кастомных тестов — минимальное. Есть удобная кастомизация, в том числе в зависимости от пользователя, у которого выполняется запуск: это весьма удобно для тестирования тестов.
Чтобы увидеть проблему в билде как можно раньше, собирать и тестировать эти билды нужно как можно чаще. Клиенты наших игр собираются под все платформы, на каждый коммит, для всех проектов. Наверное, есть какие-то исключения, но их немного.
Обычно клиент, особенно мобильный, имеет несколько разных версий: с читами и без, по-разному подписанный и т.д. На каждый коммит мы собираем «регулярные» билды, которыми разработчики и тестировщики пользуются постоянно.
Есть билды, которые используются совсем редко, например, магазинный ios-билд — всего один раз в сабмит, т.е. примерно раз в месяц. Однако мы считаем, что нужно собирать регулярно все билды. Если с данным типом сборки произойдет какая-то проблема, на стороне разработки или инфраструктуры, команда проекта узнает об этом не в день сдачи билда, а гораздо раньше, и сможет отреагировать и исправить проблему заранее.
В результате у нас есть простое правило: любой билд запускается минимум раз в сутки. О наличии любых проблем на любой платформе команда разработки проекта узнает в худшем случае на следующее утро после того, как эта проблема появилась в репозитории.
Подобная частота сборок и тестов требует особого подхода к оптимизации времени их выполнения.
Так выглядит почти полный скриншот цепочки билдов и тестов для WildScapes. Полный сделать не удалось: он примерно вдвое больше.
После сборки выполняется статическое тестирование: берем папку с билдом и выполняем набор проверок всего контента, который там есть. Код — это тоже контент, поэтому его статический анализ (cppcheck + PVS-Studio) тоже тут.
На хабре выходил подробный материал [1] о том, как у нас реализовано статическое тестирование, рекомендую. Акцентирую только, что статические тесты после билда и в прекоммитных хуках выполняются одним и тем же кодом. Это сильно упрощает поддержку системы.
Если статические тесты билд прошел успешно, можно идти дальше и попробовать запустить собранный билд. Тестируем билды на всех платформах, кроме UWP, т.е. Windows, MacOs, iOS, Android. UWP — тоже будет, но чуть позже.
Зачем тестировать десктопные билды, если они вроде бы нужны только в разработке? Ответ в вопросе: плохо, если художник или левел-дизайнер получит билд, который падает при запуске по какой-то нелепой причине. Поэтому Smoke-Test, минимальный набор проверок на запускаемость и базовый геймплей, выполняется для всех платформ.
Все, что выше было написано про билды, справедливо и для тестов на устройствах — минимум раз в сутки. За единичными исключениями: встречаются очень длительные тесты, которые за сутки не успевают выполниться.
Smoke-Test’ы выполняются на каждый коммит. Успешное выполнение базовых проверок является обязательным условием для попадания билда в систему раздачи. Обычно нет никакого смысла давать кому-нибудь доступ к билду, который заведомо не работает. Тут можно возразить и придумать исключения. У проектов есть обходной путь, чтобы дать доступ к нерабочему билду, но они им почти не пользуются.
Какие еще есть тесты:
Для запуска тестов мы используем собственный тестовый стенд ios и android устройств. Это позволяет нам как угодно гибко запускать на устройствах нужные нам билды, взаимодействовать с устройством из кода. Мы имеем полный контроль, понятный уровень надежности, знаем, с какими проблемами мы можем столкнуться и сколько времени займет их решение. Ни один из облачных сервисов, предоставляющих устройства для тестирования, такого комфорта не предлагает.
Тесты, которые перечислены выше, реализуются внутри кода проекта. Это позволяет в теории сделать тест любой сложности, но требует усилий и ресурсов со стороны разработки проекта на реализацию и поддержку этих тестов. Ресурсов этих часто нет, а тестировать многочисленную регрессию руками сложно и не нужно. Очень хотелось, чтобы автоматизацией тестирования занимались сами тестировщики. И мы придумали для них фреймворк — Continuous Automation Testing System, или CATS.
В чем идея: дать возможность авторам тестовых сценариев взаимодействовать с игровым приложением, абсолютно не заботясь о том, как это все работает. Сценарии пишем на примитивном python’е, к приложению обращаемся через набор абстракций. Например: «Homescapes, открой мне окно с покупками и купи такой-то продукт». Проверяем результат, бинго.
Вся реализация команд сценария скрыта за набором абстракций. API, реализующее взаимодействие с приложением, позволяет сделать любое действие несколькими способами:
Последний метод открывает пространство для фантазии тестировщиков, которые часто хотят тестировать «боевые» билды, где никаких читов нет. Поддерживать такие сценарии сложнее, но «боевой билд» — это «боевой» билд.
Работать с координатами центра кнопки оказалось очень удобно: координаты, бывает, меняются, а вот идентификаторы кнопок — редко. Это привело к еще одному важному свойству системы: возможности написать один тестовый сценарий для всех платформ и всех разрешений экрана.
С доставкой все оказалось совсем просто: мы используем единое разделяемое хранилище для артефактов билдов и для хранения в системе раздачи. «Загрузка» билда сводится к вызову пары запросов к api сервиса раздачи билдов, по сути — регистрации. Этим мы сэкономили немного времени на прокачку билдов и денег на их хранение.
Помните, говорили про минимизацию ресурсов, требуемых для исправления найденных в билдах ошибок? Отчеты и следы — как раз про это:
Следы нужны для того, чтобы везде была полная информация о билде и изменениях, из которых он был собран. Чтобы ничего не искать, чтобы все было под рукой и не нужно было тратить время на поиск деталей, которые часто необходимы при исследовании какой-то проблемы.
Тут всего не вспомнить, но идею вы поняли: ссылки на все, везде. Это очень ускоряет изучение любой непонятной ситуации.
Мы собираем и тестируем билды под все платформы. Для этого нам нужно много разных агентов. Следить и обслуживать их вручную долго и сложно. Все агенты готовятся автоматизированно. Мы используем Packer и Ansible.
Все логи всех агентов, Teamcity, всех сервисов, которые вокруг, мы сохраняем (в нашем случае — в ELK). Все сервисы, обрабатывая какой-то билд, добавляют в каждую строчку логов номер этого билда. Мы можем в один запрос увидеть весь жизненный цикл билда от появления его в очереди до окончания отправки всех отчетов.
Мы реализовали собственный механизм оптимизации очереди. Тот, что в Teamcity, не очень хорошо работает на наших числах. Кстати, о числах:
CI в Playrix — это сервис. Проектов много, идей тоже много.
Мы оптимизируем время от попадания билда в очередь до окончания его выполнения, потому что именно так считает «время билда» пользователь сервиса, разработчик. Это позволяет нам искать и находить баланс между временем выполнения билда и временем его нахождения в очереди. Вроде бы логично, что с ростом компании и количества проектов будет расти и билд-ферма, которая эти проекты собирает. Но благодаря оптимизациям скорость роста фермы сильно отстает от скорости роста компании.
Любая оптимизация начинается с мониторинга, с методичного сбора статистики. Статистики мы собираем много и знаем про наши билды решительно все. Но кроме объема билд-фермы есть еще команда, которая поддерживает систему CI и делает так, чтобы никому не нужно было думать о том, откуда берутся билды.
Оптимизация процессов в этой команде — тоже интересный и занимательный процесс. Например, мы пишем тесты на настройки билд-конфигураций, потому что этих конфигураций много, без подобных тестов найти все места, требующие правок, непросто. Почти на любые изменения мы сначала пишем тест, а потом их вносим, т.е., по сути, у нас TDD. Есть много процессов, связанных с дежурствами, инцидент-менеджментом, диспетчеризацией потока входящих задач.
Разработчики должны фокусироваться на создании прекрасных и успешных игр, не думая о том, откуда берутся билды. Для этого в Playrix есть CI. Должна быть цель, которую хочется достигнуть с помощью Continuous Integration, проблема, которую нужно решить. Важно не придумать проблему, а именно найти ее. А когда вы ее найдете, вспомните про наш опыт и сделайте лучше. И помните:
CI never sleeps
Увидимся!
Автор: s_orlov
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/igry/339820
Ссылки в тексте:
[1] выходил подробный материал: https://habr.com/ru/company/playrix/blog/452926/
[2] AddressSanitizer’ом: https://en.wikipedia.org/wiki/AddressSanitizer
[3] Источник: https://habr.com/ru/post/479966/?utm_source=habrahabr&utm_medium=rss&utm_campaign=479966
Нажмите здесь для печати.