Как организованы процессы разработки и тестирования

We use cookies. Read the Privacy and Cookie Policy

Как организованы процессы разработки и тестирования

Прежде чем мы взглянем поближе на задачи разработчиков в тестировании, давайте посмотрим, в каких условиях они работают. Разработчики в тестировании и разработчики связаны очень тесно, у них много общих задач в работе над любым продуктом. Так происходит, потому что в Google тестирование — обязанность всей инженерной команды, а не только людей, в должности которых есть слово «тестирование».

Готовый код ­— основной артефакт, над которым работают все участники команды. Организовать структуру, написать код и сопровождать его — их ежедневные задачи. Большая часть кода Google хранится в едином репозитории и использует общие инструменты. Все процессы сборки и выпуска построены вокруг этих инструментов и репозитория. Каждый инженер Google знает эту среду как свои пять пальцев, поэтому любой участник команды независимо от своей роли может залить новый код, создать и запустить тест, собрать версию и т.д.

На заметку

Готовый код — основной артефакт, над которым работают все участники команды. Организовать структуру, написать код и сопровождать его — их ежедневные задачи.

Еще один плюс единого репозитория: инженерам, переходящим из проекта в проект, не нужно переучиваться, а так называемые «двадцатипроцентные сотрудники» могут нормально работать с первого дня в проекте.[16] Кроме того, весь исходный код доступен любому инженеру. Разработчики веб-приложений могут просмотреть интересующий их код браузера, не спрашивая ни у кого разрешения, или узнать, как другие, более опытные сотрудники решали аналогичные задачи. Можно взять код для повторного использования на уровне модулей или даже на уровне структур контролов или данных. Google — един, и он использует общий репозиторий с удобными (еще бы!) средствами поиска.

Благодаря тому что наша кодовая база открыта, доступ к ней есть у всей компании, а технический инструментарий един, мы разработали огромный набор библиотек и сервисов для общего использования. Общий код надежно работает на боевой среде Google и ускоряет работу над проектами, а использование общих библиотек при разработке сокращает количество багов.

На заметку

Благодаря тому что наша кодовая база открыта, доступ к ней есть у всей компании, а технический инструментарий един, мы разработали огромный набор библиотек и сервисов для общего использования.

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

— Используйте уже написанные библиотеки по максимуму. Пишите свою только в том случае, если у вас есть на то серьезная причина из-за специ­фических особенностей проекта.

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

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

— Сделайте зависимости настолько очевидными, что их невозможно будет пропустить. Если проект зависит от общего кода, то пусть о любых его изменениях узнают участники всех зависимых проектов.

Если инженер предлагает более удачное решение, то он же проводит рефакторинг всех существующих библиотек и помогает перевести все зависимые проекты на новые библиотеки. Работа на благо сообщества должна поощряться.[17]

Google серьезно относится к процедуре код-ревью, и любой код, особенно общий, просматривает специалист с черным поясом по читаемости кода. Специальная комиссия выделяет таких специалистов за умение писать чистый и стилистически точный код для четырех основных языков Google (C++, Java, Python и JavaScript).

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

Для решения проблем с зависимостями платформ мы минимизируем их различия на машинах сотрудников. У всех инженеров на компьютерах стоит та же версия OS, что и на боевых машинах. Мы тщательно следим за актуальностью сборок Linux, чтобы разработчик, проводящий тестирование на своем компьютере, получил такие же результаты, как и при тестировании в боевой среде. Различия в процессорах и операционных системах между компьютерами инженеров и дата-центрами минимальны.[18] Если баг возник на компьютере тестировщика, то он, скорее всего, воспроизведется и на компьютере разработчика, и в условиях реальной эксплуатации.

Весь код, связанный с зависимостями платформ, собирается в библиотеки на самом нижнем уровне стека. Управляют этими библиотеками те же ребята, которые отвечают за дистрибутивы Linux. Наконец, для каждого из языков программирования, на которых пишут в Google, мы используем только один компилятор, который поддерживается и постоянно тестируется на одной из сборок Linux. Ничего сложного, но эта простая схема экономит силы на финальных стадиях тестирования, а заодно сокращает количество проблем, связанных со спецификой среды, которые сложны в отладке и отвлекают от разработки новых функций. Простота и надежность.

На заметку

Вся платформа Google построена на простоте и единообразии: одинаковые сборки Linux для компьютеров инженеров и машин с боевой средой, общие базовые библиотеки под централизованным управлением, общая инфраструктура хранения исходного кода, сборки и тестирования, один компилятор для каждого из языков программирования, общая спецификация сборки для всех языков. И самое важное, культура, которая уважает и поощряет поддержку этих общих ресурсов.

Тему единообразия платформ и единства репозитория продолжает единая система сборки, не зависящая от языка, на котором написан проект. Не важно, на каком языке работает команда (C++, Python или Java), она все равно будет использовать общие «файлы сборки».

Чтобы сборка состоялась, нужно указать «цель сборки». Это может быть библиотека, бинарный файл или набор тестов, который состоит из некоторого количества исходных файлов.

Последовательность шагов следующая.

1. Напишите класс или набор функций в одном или нескольких исходных файлах. Убедитесь, что весь код компилируется.

2. Укажите цель сборки (например, определенную библиотеку) для новой сборки.

3. Напишите юнит-тесты, которые импортируют библиотеку, имитируют нетривиальные зависимости и выполняют интересующие нас пути в коде для самых актуальных входных данных.

4. Создайте тестовую сборку для юнит-тестов.

5. Соберите и запустите сборку с тестами. Изменяйте код до тех пор, пока все тесты не будут проходить.

6. Запустите все обязательные инструменты статического анализа, которые проверяют соответствие кода гайдлайнам и выявляют стандартные баги.

7. Отправьте итоговый код на код-ревью (подробнее о код-ревью мы расскажем позже), внесите изменения и повторите все юнит-тесты.

В результате мы создаем две сборки: собственно библиотеку, представляющую новый сервис, и сборку тестов для этого сервиса. Учтите, что многие разработчики в Google применяют методологию TDD (Test-Driven Development, или разработка через тестирование), при которой шаг 3 предшествует шагам 1 и 2.

Если разработчик конструирует более крупный сервис, то он продолжает писать код, связывая постоянно увеличивающиеся сборки библиотек. Сборка бинарника создается из основного файла, который ссылается на нужные библиотеки. Так появляется продукт Google, у которого есть:

— хорошо протестированный автономный бинарный файл;

— легкочитаемая и приспособленная для повторного использования библиотека (с набором вспомогательных библиотек, которые можно использовать для создания других сервисов);

— набор юнит-тестов, покрывающих нужные аспекты всех сборок.

Типичный продукт Google — это набор нескольких сервисов. В любой команде мы стараемся добиться соотношения 1:1 между разработчиками и сервисами. Это означает, что сервисы собираются и тестируются параллельно, а затем интегрируются в итоговой сборке. Чтобы связанные сервисы могли создаваться одновременно, их интерфейсы взаимодействия согласовываются в начале проекта. Тогда разработчики могут реализовывать зависимости через такие интерфейсы, а не через библиотеки. В начале работы разработчики создают имитации таких интерфейсов, чтобы начать писать тесты на уровне всего сервиса.

Разработчики в тестировании вовлечены в создание большинства тестовых сборок и определяют, где нужно писать малые тесты. По мере того как маленькие сборки собираются в целое приложение, задачи растут, и уже нужно проводить более крупные интеграционные тесты. Если для сборки одной библиотеки достаточно выполнения малых тестов, написанных самим разработчиком, то с увеличением объема сборок разработчики в тестировании вовлекаются во все большей степени и пишут уже средние и большие тесты.

Сборка увеличивается в размерах, и малые тесты становятся частью регрессионного пакета. Они должны быть всегда актуальны. В противном случае в них инициируются баги, отладка которых ничем не отличается от отладки багов основного кода. Тесты — часть функциональности, а значит, баги в тестах относятся к функциональным багам и исправляются. Такая схема гарантирует, что новая функциональность не нарушит работу существующей, а изменения в коде не сломают тесты.

Разработчики в тестировании — центр всей этой деятельности. Они помогают разработчикам решить, какие юнит-тесты написать. Они создают подставные объекты и имитации. Они пишут средние и большие интеграционные тесты. Именно об этих задачах разработчиков в тестировании мы собираемся сейчас рассказать.

Данный текст является ознакомительным фрагментом.