Автор лекции Константин Заикин.
кзаикин , руководитель группы разработки Яндекс Браузера для Android в Санкт-Петербурге.
Он рассказал об инструментах Android-разработчика и всей команды, а также о том, как бороться с устаревшим кодом, вовремя публиковать большой проект и улучшать качество кода.
- Друзья, здравствуйте.
Я очень рад, что сегодня пришло так много вас.
Я приехал из Санкт-Петербурга и работаю в Яндексе около шести лет. Удалось появиться в Картах, Такси, Метрике и Поиске.
Я работаю над Яндекс Браузером для Android уже два года.
Сегодня я собираюсь поговорить о том, как обеспечить хороший код в браузере.
Браузер для Android – довольно громоздкая штука.
В принципе, ядром в браузере является ядро Chromium, вокруг которого стоит ядро сервисов Яндекса, всё это написано в основном на C++, а приложения платформы пишутся вокруг этих двух ядер, вложенных друг в друга.
Яндекс.
Браузер доступен на Windows, Mac, Linux, Android и iOS. В основном я буду говорить о коде для Android, а конкретно о Java и Kotlin.
В Яндексе 200 мобильных разработчиков, но в одном Браузере — с десктопом и всем остальным — тоже 200 человек.
Около 30 из них пишут для Android. Людей много, и кода мы написали много.
По количеству линий мы самые крупные в Яндексе.
И естественно, как и в любом живом организме, в нашем проекте код рождается, живет, стареет, за ним нужно следить и обеспечивать его хорошее здоровье.
Я расскажу вам по порядку, какие процессы мы применили для обеспечения качества кода и какие инструменты используем.
Любой возникающий баг имеет несколько моментов, когда его можно решить.
Баг можно просто не делать.
Исправить ошибку можно, когда она находится в открытом окне редактора разработчика.
Вы можете найти его в модульных тестах.
Вы можете найти его позже при тестировании или в производстве.
Мы постарались построить наши процессы так, чтобы на всех этих этапах было обнаружено максимальное количество ошибок или не возникло вообще.
Прежде всего, мы прописали наш стиль кода в браузере.
В большом проекте действительно очень важно, чтобы существовал написанный стиль кода, который был актуальным и поддерживался, и мы поместили его как стиль кода MD в наш репозиторий.
Чтобы его отредактировать, нужно сделать пул-реквест, чтобы он, как и обычный код, был просмотрен, лайкнут, команда согласилась, и после этого все согласились с этими правилами.
Или обсуждаем и вносим новые изменения.
Кодстиль, помимо закрепления общего для всей команды правила, несет еще и обучающую функцию.
У нас большая команда, мы приглашаем к нам много новых людей.
Новички сначала читают Wiki, у нас много описаний, мы любим Wiki. И они читают codestyle. Есть примеры того, что делать и чего не делать.
После того, как разработчик написал новую функцию в соответствии со стилем кода, он должен ее закоммитить.
Мы создали перехватчики предварительной фиксации, которые предотвращают фиксацию кода, который отклоняется от принятых правил.
Это может быть стиль кода или какие-то вещи, которые статический анализ может легко уловить.
То есть просто не дать коду проникнуть в коммит; git отказывается принимать такой код. После этого нам предстоит пройти проверку кода.
Мы используем Bitbucket, у нас есть правило, что любой код может попасть в репозиторий только после одобрения двух коллег.
Два живых человека должны прийти, посмотреть на код, и он им понравится.
И этот пул-реквест должен быть собран и пройти все 100% наших модульных тестов.
И тестов у нас много.
А рецензенты смотрят, и все заранее зацепляются.
Некоторым из вас может быть интересно, сколько времени это вообще занимает? Это большой проект. Могу с гордостью сказать, что наше минимальное время от создания пул-реквеста до загрузки кода в репозиторий теперь составляет около 30 минут. Это минимальное время попадания кода в наш мастер.
Мы уже давно работаем над этим.
А у нас обычный браузер на базе Chromium. У всех, кто пишет такие браузеры, очень большие проблемы со временем сборки.
Миллион строк кода, их нужно компилировать, они долго компилируются.
А еще нужно скомпилировать 400 тысяч строк Java-кода и запустить тесты.
Это результат работы всей команды.
Мы все работаем над тем, чтобы наши процессы позволяли нам больше думать о результате, а не о том, как ждать сборки, локально или в TeamCity. Важно то, что на TeamCity это время составляет 30 минут, а сборка локального разработчика занимает 30 секунд. Он не запускает все юнит-тесты, не собирает все сборки для всех платформ, всех комбинаций.
И на TeamCity мы это собираем.
Плюс тесты проводятся на TeamCity. Сейчас из этих 30 минут юнит-тесты занимают около 20 минут. Кроме того, для обеспечения качественного кода мы ввели техническую квоту.
Мы тратим 30% времени команды на возврат технического долга, который нам удалось накопить и который мы пытаемся делать снова и снова.
Каждый спринт 30% команды занимается рефакторингом, улучшением существующего кода, написанием незавершенных модульных тестов или улучшением инструментов.
Вообще, чтобы улучшить любую вещь, есть очень важное правило – прежде чем что-то улучшать, нужно это измерить.
Прошу вашей помощи.
Подскажите, пожалуйста, какие вещи вы бы предложили измерить, чтобы понять, насколько качественный ваш код и качественный продукт, чтобы этот продукт улучшить.
В качестве примера назову очевидную вещь: каково у вас покрытие тестами в процентах.
Какие еще есть варианты понять, качественный у вас код или нет? Количество строк в методе.
Количество классов.
Скорость выполнения, сколько времени занимает запуск вашего приложения, как быстро прокручиваются списки.
Количество интерфейсов – это, в принципе, та же метрика.
?Энергопотребление в порядке? Время сборки тоже.
У нас есть инструменты для всего, что вы упомянули.
Мы знаем, как измерить то, что есть в нашем проекте сейчас, как было год назад и что происходит сейчас.
Мы в первую очередь измеряем работоспособность приложения в продакшене, используем AppMetrica, это публичный сервис, который позволяет отслеживать события, сбои и работоспособность приложения.
Мы собираем множество технических индикаторов с помощью AppMetrica. Затем, используя ClickHouse и наши собственные инструменты, мы создаем отчеты на основе этих данных.
У нас их немного больше, чем у среднестатистического пользователя AppMetrica, только за счет того, что мы вложили средства в доступ к этой базе данных и делаем специальные запросы.
AppMetrica позволяет собирать факт события.
Произошло событие – столько всего.
Но AppMetrica не позволяет смотреть числовые данные.
Например, нам нужно измерить потребление энергии у некоторых попугаев.
И нужно понимать, насколько у разных пользователей сколько этих попугаев в текущей версии.
Как выглядит распределение пользователей по энергопотреблению? Как выглядит распределение пользователей по времени запуска? Как выглядит распределение пользователей по скорости прокрутки в FPS или по времени между кадрами.
И чтобы собрать такие числовые данные и проанализировать их, мы использовали гистограммы.
Мой коллега о них очень хорошо рассказал, они есть в Яндексе под словом «гистограммы», самое первое видео — это рассказ коллеги из моей команды о том, как мы собираем числовые показатели и анализируем их.
Тот же Илья Богин сможет подробно рассказать, как собирать эти числовые показатели.
И затем у нас есть очевидный показатель открытых ошибок.
Есть продукт, есть тестирование, есть пользователи.
Они сообщают об ошибках.
Чем больше ошибок, тем хуже продукт. Чем больше ошибок в блокировщике, тем хуже продукт. Сравните баги блокировщика с минорными.
У нас есть отдельная метрика, которая показывает качество продукта в багах, политика нулевых багов, условно.
Это скриншот нашего настоящего инструмента, который собирает количество сбоев на миллион сессий.
Не очень видно, но нижний график — количество сбоев в Java, около 200 на миллион сессий.
И два верхних.
Во-первых, краши в нативе, их довольно много, потому что у нас ядро Chromium и там очень много "плюсов".
Верхняя часть — это сумма.
В целом мы следим за этим показателем и работаем над его улучшением.
Чем меньше график, тем лучше.
Это за последний год мы работали и совершенствовались.
То же самое, у нас одинаковые графики энергопотребления, скорости прокрутки и всего остального.
Кроме того, мы внедрили и очень активно используем эту штуку SonarQube, всем рекомендую.
Вы можете установить его для себя, независимо от того, являетесь ли вы инди-разработчиком или частью команды.
Это платформа, на которой можно реализовать любые статические анализаторы кода.
Он имеет открытый исходный код, бесплатен и может анализировать практически все существующие языки программирования.
Мы его реализовали и теперь постоянно отслеживаем с его помощью некоторые показатели работоспособности нашего проекта.
Я кратко расскажу о том, что изображено на этом слайде.
Это очень важно, об этом написано в документации, но не очень очевидно.
Это настоящий дашборд, скриншот. У нас очень много ошибок, больше тысячи.
Существует ряд уязвимостей безопасности.
Это охват тестами — 52,7%.
И так много модульных тестов.
Кажется, круто.
Сейчас у нас самый большой охват мобильных приложений Яндекса.
Мы также измеряем долю дублированного кода.
Что интересно, мы настроили эту штуку для всех мобильных приложений Яндекса и можем смотреть дубликаты между проектами, это тоже очень круто, помогает нам подсвечивать те части кода, которые следует положить в библиотеку, чтобы не дублировались снова.
Самая главная метрика, которая собирает все это, это и еще кучу всего и в одном понятном числе говорит, какой у вас проект, хороший или плохой.
Это технический долг — его у нас 204 дня, условные рабочие дни условного разработчика в вакууме, который должен работать, чтобы все эти проблемы были устранены.
Как вы думаете, это большой долг или маленький? У нас большая команда, 30 человек.
Если мы возьмемся за это, мы погасим этот долг в ограниченные сроки.
У нас были эпизоды, когда мы встали и начали — давайте исправим все блокировщики в SonarQube. И начали их исправлять.
Но здесь есть одна особенность.
Это серебряная пуля.
Неважно, сколько ошибок статический анализ нашел в вашем проекте.
Важно не создавать новых ошибок.
А исправление ошибки, что хорошо и есть уже давно, когда-нибудь обязательно произойдет. Но этого не произошло, его не нашли при тестировании, его юнит-тесты не нашли.
Скорее всего, он не выстрелит. А исправление старой ошибки может привести к тому, что у вас появится новая, настоящая, что приведет к настоящему краху.
Главное не исправлять старые ошибки, а следить за тем, чтобы не было новых.
В нашем личном кабинете есть отдельный индикатор — мы накопили 1 день новой задолженности за последние 14 дней.
Да, мы это делаем, но очень умеренно.
Наш коэффициент технического долга, доля долга в объеме всего кода, неуклонно снижается.
И это лучший показатель того, что мы все делаем правильно.
Вырезки из реальных скриншотов на экране.
Этот же Sonar позволяет добавлять комментарии к запросам на включение.
У нас два рецензента приходят и оставляют комментарии, плюс еще приходит робот, третий рецензент. Он оставляет комментарии по очевидным вопросам, по стилю кода, дизайну кода, находит уязвимости с точки зрения безопасности.
Люди любят его.
Не позволяет добавлять новые долги.
Кроме того, в Sonar мы можем посмотреть существующие ошибки.
Есть очень удобный просмотрщик, где мы видим всю кодовую базу и по каждой строчке видим, какая проблема, когда она была добавлена и что с ней делали.
Вы можете прийти к автору и сказать: друг мой, за последние две недели ты добавил пять блокировщиков - как это возможно? Выясните причины и устраните их.
Мы всегда стараемся решить любую проблему в корне, исключить возможность возникновения такой проблемы.
Как правило, мы готовим какие-то инструменты или убеждаемся, что нельзя допускать ошибок.
Мы очень активно пишем тесты.
Мы любим тесты.
За последнее время мы добились большого прогресса в их написании.
У нас сейчас такое количество тестов, выполняемых с помощью JUnit, это тесты, которые выполняются на хост-машинах, только Java и Robolectric. И инструментальные тесты Android. Эта сумма у нас сейчас есть.
Пока мы писали такое количество тестов, мы прошли несколько этапов.
Тесты нужно писать, их пишут все, хотим качественный продукт — давайте тоже его напишем.
У нас действительно много проблем.
Мы пишем новые тесты, но старые постоянно ломаются, требуют много времени на поддержку, а ошибок не обнаруживается.
Любое изменение кода приводит к сбою десятков сотен тестов, и мы исправляем тесты.
К счастью, мы уже миновали этот кризис; теперь наши тесты фактически предоставляют не только документацию кода, но и дают разработчику уверенность в том, что код написан правильно.
Сейчас вся команда научилась писать тесты и пишет их очень активно.
На предыдущем слайде показано, что охват новым кодом составляет 55%.
Это больше, чем старый, мы движемся в правильном направлении.
Лучше бы еще выше, но пока это все.
Мы активно используем Robolectric, мы им довольны, он позволяет нам мокить, заменять настоящий Android, но при этом гораздо быстрее запускать тесты.
9000 тестов – это очень много.
Из них около 600 выполняются на эмуляторах, остальные тесты выполняются на хост-машине.
Наш билд-агент быстрый, 16 ядер, на них все быстро и просто.
Если взять в руки симулятор, то на нем начинают долго и мучительно проводиться испытания приборов.
Это то, чего мы стараемся избегать.
Робоэлектрик очень хорош.
Мы также активно используем интерфейсы.
Мы сторонники чистого кода, активно используем инверсию управления, внедрение зависимостей и с помощью интерфейсов отделяем платформу от кода, который пишем.
Есть люди, которые отрицают Робоэлектрик, говорят, что нужны только интерфейсы, а Робоэлектрик — это зло.
Мы сторонники разумного подхода.
Мы активно используем Mockito и намеренно исключили Powermock, поскольку он вызывал плохой стиль тестирования.
Это зло, позволяет издеваться над статикой, финалами, вообще ломает все вокруг и провоцирует плохую архитектуру.
Основная суть этого слайда заключается в том, что мы документируем все, как и любую другую вещь.
Мы записываемся в стиле «не делай этого».
У нас есть тестовые запахи, отдельная страница, где фиксируются типичные проблемы, возникающие при написании тестов в режиме «так плохо, но было бы хорошо».
И новые разработчики, когда приходят, обычно говорят, что эта штука очень помогает, потому что там не просто примеры того, чего не надо делать, а многие просто смотрят на правильную сторону того, что надо делать.
Существует множество техник и инструментов, о которых вы даже не догадываетесь; вам нужно понять их с опытом или выучить их с опытом.
И вот мы им все это говорим на блюдечке.
Этот график говорит сам за себя.
Это данные с июня прошлого года по текущий момент. Мы работали над тестовым покрытием и писали тесты.
Но самое главное – мы не стояли на месте, мы росли.
Помимо юнит-тестов мы используем автотесты.
Для тех, кто не знает или использует это кодовое название тестов, проверяющих приложение как черный ящик.
Запускают его на устройстве или эмуляторе, а условный робот резиновым пальцем листает списки, тыкает в кнопки и пытается сломать ваше приложение по стандартным сценариям.
Автоматическими тестами мы заменяем ручных тестировщиков, реальных людей, которым лучше заняться чем-то более значимым, чем повторять сценарии снова и снова.
Мы ускоряем наш регресс, проверяя, что новый релиз хорош и может быть запущен в производство.
Теперь мы выпускаем релизы каждые три недели, и большая часть этой заслуги в том, что мы перевели ручное тестирование на автоматизированное.
Более 60% наших тестов автоматизированы.
Наши автотесты написаны на Appium, это достаточно стандартный инструмент для Яндекса, он пришел к нам из веб-тестирования вместе с людьми, которые тестировали веб.
Сейчас мы написали около 3000 тестов на Appium, развернули инфраструктуру, которая позволяет каждый раз запускать по 25 эмуляторов, они подходят, новые и чистые, тесты запускаются и выполняются на них параллельно.
Но все равно все получается очень медленно.
Запуск регрессии теперь занимает у нас несколько часов, и мы не можем делать это постоянно, для каждой сборки.
У нас недостаточно ресурсов и оборудования, чтобы сделать все это.
И мы очень активно помогаем этим инструментам с открытым исходным кодом на GitHub. Инструменты контроля качества Яндекса инструментов много, есть активное сообщество, где мы все это публикуем.
Вот еще что мы, можно сказать, пережили.
Изначально автотесты писали частные лица, а не разработчики.
Есть органы управления ручником, их надо автоматизировать.
Первая реакция — давайте заменим ручник на робота, пусть пишет, и отдельно от браузера будет репозиторий, куда пишется код. Вроде ребята пишут код на Java, тот же JUnit, они вроде тестировщики.
Но со временем мы объединили команды, слились воедино, и теперь автотесты может писать любой разработчик.
Мы специально ротируем людей, чтобы все знали, как пишутся автотесты, чтобы они знали, как исправить автотесты, когда мы их вдруг сломаем.
Основная боль автотестов в том, что они всегда отваливаются и ломаются, что они всегда красные.
Я покажу вам один из способов решения этой проблемы.
Это телевизор из моего офиса, один из них.
Нам вообще нравятся телевизоры с графикой.
Но это ТВ про автотесты.
Зеленый – успешно пройден, желтый – не удалось по известной нам причине, красный – по неизвестной причине.
Мы наблюдаем за этим постоянно.
Мы выделили отдельного дежурного, который все время меняется, который следит за тем, что происходит с тестами.
Очень важно следить за тем, чтобы отвалившиеся тесты не гнили.
Если вы сразу не возьметесь за тест и не найдете причину, то со временем этот тест умрет и вы выбросите усилия, потраченные на его разработку.
Поэтому мы постоянно отслеживаем и знаем, почему каждый тест не удался.
Эти тесты фактически обнаруживают регрессии и проблемы, возникающие в рабочем коде.
Не даем коду дойти до продакшена, все находим в автотестах, не даем увидеть ручникам.
Мы также активно используем Espresso. И теперь мы считаем, что тесты на Espresso гораздо важнее тестов на Appium, потому что писать тесты на Espresso быстрее.
Их быстрее поддерживать и быстрее выполнять, но им также нужно много быстрых эмуляторов.
Инфраструктура – главная проблема.
Мы запускаем тесты Espresso на эмуляторах.
Раньше мы гоняли их на железных устройствах, но это действительно проблема.
У нас до сих пор есть шкафы, где лежат десятки телефонов и моргают экранами.
С ними постоянно что-то происходит. Поэтому во всех тестах мы перешли с устройств на эмуляторы и этому очень рады.
Если вы собираетесь строить такую инфраструктуру, советую сразу смотреть только на эмуляторы.
В тестах, конкретно в Espresso, мы стали активно использовать Kotlin, на котором написали очень удобный DSL, описывающий нашу систему, наш браузер и позволяющий очень быстро реализовывать новые тесты.
Потому что все шаги готовы, и ты как будто собираешь все из кубиков и делаешь новый тест. Качество – это не разовое мероприятие.
Вы не можете взять и сделать это эффективно.
Качество – это процесс.
Для достижения качества мы изменили процессы.
Мы добавили роботов, которые проверяют все, что делают люди.
Мы просим людей делать все одинаково.
Мы контролируем, что происходит с нашим продуктом, с нашим кодом, пишем множество тестов и постоянно их все запускаем.
Все модульные тесты запускаются всегда.
И мы пишем много автоматизированных тестов, которые позволяют разгрузить ручных тестировщиков и раньше находить ошибки.
Но все равно главное – это люди.
Вся команда должна понимать, что мы делаем продукт, нам не нужно жить с этим продуктом и создавать ошибки, а нужно писать хороший, чистый и крутой код. Мне казалось, что я сам придумал эту фразу.
Оказалось, что нет. Теги: #Android #Разработка Android #открытый исходный код #тестирование #Тестирование мобильных приложений #java #автотесты #Kotlin #Идеальный код #espresso #qa Automation #Chromium #teamcity #sonarqube #Яндекс-браузер #codestyle #junit #JUnit #юнит-тесты #appium #робоэлектрик
-
Проблемы С Дискетами
19 Oct, 24 -
Dotnext 2019 Питер: Краткий Отчет
19 Oct, 24 -
Проблема Со Шнурами
19 Oct, 24