Страница 15 из 16
На следующем шаге мы строим легковесный фреймворк автоматизации, который даст нам возможность запустить систему подставных объектов. При таком подходе любой разработчик, код которого использует один из наших подставных интерфейсов, может создать себе отдельную сборку и прогонять на ней автоматизированные тесты перед тем, как заливать изменения в репозиторий. Только хорошо протестированный код попадает в репозиторий. Это одно из ключевых достоинств автоматизации: плохой код не попадает в экосистему и не загрязняет общую кодовую базу.
План автоматизации должен не только перечислить средства автоматизации, которые создает разработчик в тестировании: подставные объекты, имитации и фреймворки. План должен объяснять, как все участники проекта будут получать информацию о качестве сборки. Мы включаем в план создание механизмов отчетности и панели мониторинга результатов тестов и статуса выполнения. Наши разработчики в тестировании увеличивают шансы создания высококачественного кода, упрощая процесс его разработки и делая его более прозрачным.
Тестируемость
Разработчики в тестировании плотно работают вместе с разработчиками. Пока разработчики пишут код функциональности и тесты для него, разработчики в тестировании создают для них тестовые фреймворки, а заодно выполняют часть работы по ее сопровождению. Ответственность за качество делится между этими ролями поровну.
Основная цель разработчиков в тестировании — сделать продукт тестируемым. Они дают рекомендации, как выстроить структуру программы и стиль написания кода, чтобы упростить будущее юнит-тестирование. Они создают удобную среду тестирования, чтобы разработчики могли тестировать сами. Об этом чуть позже, а сейчас поговорим о том, как пишется код в Google.
Чтобы прийти к равноправной ответственности разработчиков и разработчиков в тестировании за исходный код, мы в Google строим процесс разработки вокруг код-ревью. О том, как рецензировать код, говорят даже больше, чем о том, как его писать.
Рецензирование кода — полноценный этап работы разработчиков. У него есть свои инструменты и своя культура, которая строится на концепции коммитеров, как в опенсорс-сообществах, где коммитить код в базу могут только самые надежные и доказавшие это право разработчики.
Google строит процесс разработки вокруг код-ревью. О том, как рецензировать код, говорят даже больше, чем о том, как его писать.
В Google любой инженер может стать коммитером. Мы пользуемся концепцией читаемости кода, чтобы отличать проверенных сотрудников от новичков. Вот как работает этот процесс.
Когда код написан, он упаковывается в пакет, который мы называем списком изменений. Дальше он отправляется для рецензирования в приложение, которое в Google называют Mondrian, в честь голландского художника, положившего начало абстрактному искусству. Mondrian отсылает код ответственному разработчику или разработчику в тестировании для окончательного утверждения.[20]
Блоки нового кода, изменения в существующем коде, исправления багов — все это может входить в список изменений. Размеры списков могут варьироваться от пары строк кода до нескольких сотен, причем большие списки почти всегда разбиваются на несколько мелких, чтобы рецензентам было удобнее.
Новички рано или поздно получают от коллег бейдж «спец по легкочитаемому коду», если постоянно коммитят качественные списки изменений. Эти бейджи — разные для разных языков программирования. Основные языки в Google — C++, Java, Python и JavaScript. Бейдж указывает нам опытного разработчика, который старается писать так, чтобы вся кодовая база однородной, будто ее писал один разработчик.[21]
Прежде чем список изменений попадет к рецензенту, он пройдет ряд автоматических проверок в Mondrian. Программа проверит выполнение простых условий, например насколько код соответствует гайдлайнам стиля программирования Google, и более сложных, например что все тесты, связанные с этим списком изменений, проходят. Тесты для списка почти всегда включены прямо в него — тестовый и функциональный код живут вместе. Выполнив проверку, Mondrian отправит рецензенту по электронной почте ссылку на списки изменений. В свою очередь рецензент проанализирует код и выдаст рекомендации его автору. Процесс повторяется до тех пор, пока все рецензенты не будут довольны и автоматическая проверка не будет проходить гладко.
Дальше код встает в очередь на отправку, цель которой — поддерживать сборку в состоянии «зеленый свет», в котором все тесты проходят. Это последняя линия защиты между системой непрерывной сборки проекта и системой контроля версий. Код собирается и тестируется на чистой среде, поэтому здесь отлавливаются баги, которые на машинах разработчиков могли не обнаружиться. Эти конфигурационные баги могли бы нарушить процесс непрерывной сборки или, хуже того, пробраться в систему контроля версий.
Очередь на отправку позволяет участникам больших команд совместно работать в ветке main дерева исходного кода. Больше не нужно замораживать код на время интеграции веток и прохождения тестов. Получается, что разработчики больших команд могут работать так же эффективно и независимо, как если бы команда была маленькая и гибкая. Только у разработчика в тестировании прибавляется работы — ведь скорость написания и заливки кода в репозиторий увеличивается.
Как появились очереди на отправку и непрерывная сборка
Джефф Карролло
Когда-то Google был маленьким. Тогда казалось, что провести юнит-тестирование перед коммитом изменений вполне достаточно. Но даже тогда случалось, что тесты не проходили, и люди тратили свое время на поиск и решение проблем.
Компания росла. Чтобы масштабироваться, наши разработчики писали и поддерживали качественные библиотеки и инфраструктуру, которые использовали все команды. Со временем росло количество, размеры и сложность базовых библиотек. Код проектов стал интенсивно использовать сторонние библиотеки и инфраструктуру, и одних юнит-тестов стало недостаточно — уже требовалось интеграционное тестирование. В какой-то момент стало понятно, что многие баги вызывались зависимостями между компонентами. Так как тесты не запускались до тех пор, пока кому-нибудь не вздумывалось закоммитить изменение в своем проекте, интеграционные баги могли оставаться незамеченными по несколько дней.
Потом мы пришли к панели мониторинга юнит-тестов. Система автоматически считала каждый каталог верхнего уровня в дереве кода компании «проектом». Плюс каждый мог определить свой «проект», в котором связывал сборки кода с тестами и назначал ответственного за сопровождение. Каждый день система прогоняла все тесты по всем проектам. Система записывала статистику прохождений каждого теста и показывала ее на главной панели. Если тесты падали, ответственные за их сопровождение получали письма каждый день, поэтому тесты оставались неисправными недолго. Тем не менее проблемы оставались.
Ежедневного прогона всех тестов оказалось недостаточно — команды хотели быстрее отлавливать разрушительные изменения. Некоторые команды начали писать скрипты непрерывной сборки, которые непрерывно делали сборку и выполняли юнит- и интеграционные тесты на отдельных машинах. Осознав, что эту систему можно сделать общей для всех команд, Крис Лопес и Джей Корбетт сели и написали «Систему непрерывной сборки Криса и Джея». Теперь любой проект мог развернуть свою систему непрерывной сборки. Достаточно было просто зарегистрировать машину, заполнить файл конфигурации и запустить скрипт.
Система быстро стала популярной, и вскоре большинство проектов в Google перешло на нее. Если тест не проходил, то программа оповещала всех ответственных за изменение по почте. О сбоях стали узнавать через несколько минут после коммита изменений в базу кода. Кроме того, система отмечала «Золотые списки изменений» — контрольные точки в системе контроля версий, в которых успешно проходили все тесты проекта. Теперь разработчики могли ориентироваться на стабильную версию исходников без недавних проблемных изменений. Это очень помогало при выборе стабильной сборки для выпуска.
20
Версия Mondrian с открытым кодом на базе App Engine доступна по адресу: http://code.google.com/p/rietveld/
21
Руководство Google по стилю для C++ доступно по адресу: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml