Другие тесты требуют знаний, выходящих за рамки кода, и зависят от внешней инфраструктуры. Например, у нас есть тест, который возвращает данные из удаленного хранилища (с сервера баз данных или из облака). Для тестирования нам нужна либо сама база данных, либо ее имитация. В индустрии уже выработались инструменты для этого: тестовая оснастка (harness), тестовая инфраструктура, подставные объекты (mocks) и имитации (fakes). В мире идеального процесса разработки эти макеты сразу существуют для любого интерфейса, с которым имеет дело разработчик, и каждый аспект любой функции можно протестировать в любое время. Но не увлекайтесь, мы находимся в воображаемом мире.
Мы подошли к первой развилке, где нашему сказочному миру разработки потребовался еще один герой, то есть тестировщик. При написании кода функциональности и кода тестов важны разные образы мышления. Это разные типы разработки. При разработке функционального кода на первом плане стоит создание. Нужно принимать во внимание пользователей, их сценарии использования продукта, последовательности действий и т.д. А при написании тестового кода есть ориентир на разрушение, то есть разработку такого кода, который выявит случаи, мешающие эффективной работе пользователя и его действиям. Так как мы находимся в сказочной стране идеальной разработки, мы можем нанять двух Джеков, один из которых построит дом, а другой покажет, как его можно сломать.
На заметку
При написании кода функциональности и кода тестов важны разные образы мышления.
В нашем сказочном мире идеального процесса разработки у нас будет сколько угодно разработчиков функциональности и разработчиков тестов, которые идут рука об руку и вместе строят сложный программный продукт. Это еще присказка, ведь настоящая сказка позволит нам выделить по целому разработчику на каждую фичу, к каждому разработчику приставить столько разработчиков тестов, сколько нужно. Они занимались бы глобальной тестовой инфраструктурой, помогали бы решить проблемы, найденные юнит-тестированием, чтобы разработчики не отвлекались на них от процесса создания, требующего полной концентрации.
Итак, одни разработчики пишут функциональный код, другие разработчики пишут тестовый код, и тут мы вспоминаем про третью сторону: сторону пользователя.
Естественно, в нашем сказочном мире эта задача упадет на плечи отдельных инженеров. Их задачи связаны с пользователем: сценарии использования продукта, пользовательские истории, исследовательское тестирование и т.д. Разработчики со стороны пользователя рассматривают то, как разные фичи связываются воедино и образуют единое целое. Они работают над проблемами всей системы и обычно принимают точку зрения пользователя, проверяя, действительно ли совокупность частей образует что-то полезное для них.
Итак, вот наше представление об идеальной разработке ПО: три разные роли разработчиков работают вместе над надежным, практичным совершенством, причем каждый специализируется на чем-то своем и все взаимодействуют на равных.
Кто хочет работать в компании, в которой программные продукты создаются подобным образом? Мы точно хотим!
К сожалению, никто из нас в таких компаниях не работает. Google, как и многие компании до нее, потратил множество усилий на то, чтобы приблизиться к идеалу. Возможно, потому что мы поздно начали, мы учились на ошибках предшественников. Google повезло поймать момент перехода модели программных продуктов от огромных клиентских приложений с многолетними циклами выпуска к облачным сервисам, которые выпускаются каждые несколько недель, дней или часов13. Благодаря удачному стечению обстоятельств у нас получилось хоть как-то приблизить разработку в Google к идеальному процессу разработки ПО.
Итак, разработчики в Google занимаются реализацией функциональности, отвечают за построение компонентов, строят основу приложения, поставляемого пользователю. Они пишут функции и код юнит-тестов для этих функций. Джек строит дом.
Разработчики в тестировании в Google отвечают за создание средств тестирования. Они помогают разработчикам с написанием юнит-тестов и создают большие тестовые инфраструктуры, упрощая разработчикам процесс создания малых и средних тестов и помогая выявлять больше проблем. Джек делает дом устойчивым.
Инженеры по тестированию в Google встают на сторону пользователя во всех аспектах, связанных с качеством. В контексте разработки они создают автоматизацию пользовательских сценариев, а в контексте продукта — оценивают универсальность и эффективность всех действий по тестированию, которые выполняют другие инженеры. Джек готовит дом к приходу гостей.
Это уже не сказка, а наша попытка сделать ее былью.
В этой книге мы рассказываем в основном о работе разработчиков в тестировании и инженеров по тестированию. Роль разработчиков мы затрагиваем только там, где она соприкасается с тестированием. На самом деле разработчики вовлечены в тестирование довольно сильно, но обычно эти процессы курируют специалисты, в должности которых есть слово «тестирование».
Жизнь разработчика в тестировании
Когда компания только появляется, тестировщиков в ней, как правило, нет. Точно так же как нет руководителей проектов, системных администраторов и других должностей. Каждый сотрудник выполняет все эти роли одновременно. Мы любим представлять, как Ларри и Сергей14 ломали головы над пользовательскими сценариями и юнит-тестами на заре Google. С ростом компании появились разработчики в тестировании, которые первыми привнесли фокус на качество в строго технологический дух программирования15.
Как организованы процессы разработки и тестирования
Прежде чем мы взглянем поближе на задачи разработчиков в тестировании, давайте посмотрим, в каких условиях они работают. Разработчики в тестировании и разработчики связаны очень тесно, у них много общих задач в работе над любым продуктом. Так происходит, потому что в Google тестирование — обязанность всей инженерной команды, а не только людей, в должности которых есть слово «тестирование».
Готовый код — основной артефакт, над которым работают все участники команды. Организовать структуру, написать код и сопровождать его — их ежедневные задачи. Большая часть кода Google хранится в едином репозитории и использует общие инструменты. Все процессы сборки и выпуска построены вокруг этих инструментов и репозитория. Каждый инженер Google знает эту среду как свои пять пальцев, поэтому любой участник команды независимо от своей роли может залить новый код, создать и запустить тест, собрать версию и т.д.
На заметку
Готовый код — основной артефакт, над которым работают все участники команды. Организовать структуру, написать код и сопровождать его — их ежедневные задачи.
Еще один плюс единого репозитория: инженерам, переходящим из проекта в проект, не нужно переучиваться, а так называемые «двадцатипроцентные сотрудники» могут нормально работать с первого дня в проекте16. Кроме того, весь исходный код доступен любому инженеру. Разработчики веб-приложений могут просмотреть интересующий их код браузера, не спрашивая ни у кого разрешения, или узнать, как другие, более опытные сотрудники решали аналогичные задачи. Можно взять код для повторного использования на уровне модулей или даже на уровне структур контролов или данных. Google — един, и он использует общий репозиторий с удобными (еще бы!) средствами поиска.
Благодаря тому что наша кодовая база открыта, доступ к ней есть у всей компании, а технический инструментарий един, мы разработали огромный набор библиотек и сервисов для общего использования. Общий код надежно работает на боевой среде Google и ускоряет работу над проектами, а использование общих библиотек при разработке сокращает количество багов.
На заметку
Благодаря тому что наша кодовая база открыта, доступ к ней есть у всей компании, а технический инструментарий един, мы разработали огромный набор библиотек и сервисов для общего использования.
Так как код вливается в общую инфраструктуру, к его разработке инженеры относятся очень осторожно. Подтверждают такое особое отношение неписаные, но соблюдаемые правила работы с кодом.
— Используйте уже написанные библиотеки по максимуму. Пишите свою только в том случае, если у вас есть на то серьезная причина из-за специфических особенностей проекта.
— Когда вы пишете код, помните, что он должен быть легко читаем. Сделайте так, чтобы его можно было без труда найти в репозитории. С вашим кодом будут работать другие люди, поэтому нужно сделать его понятным и легко изменяемым.
— Общий код должен быть автономным и пригодным для повторного использования. Инженеров поощряют за создание сервисов, которые могут использовать другие команды. Возможность повторного использования кода гораздо важнее, чем его сложность.