Как организовать тестирование, чтобы ускорить и стабилизировать релизы продукта. Часть 2
У тестировщика много возможностей повысить качество продукта и сделать работу команды комфортнее. Главное – обсуждать любые изменения с коллективом и внедрять только то, что удобно и полезно для всех.
Меня зовут Виктория Дежкина, я отвечаю за тестирование ряда продуктов в Дирекции больших данных X5 Retail Group. В прошлой части статьи я начала рассказывать о том, как мы меняли процессы в команде продукта «Система автоматизации закупок торговой сети». Релизы продукта постоянно задерживались на несколько дней и часто выходили «сырыми». Мы изменили порядок выкладки кода и планирования задач, что позволило сократить релизный цикл на несколько дней, но нам еще предстояло выработать оптимальный формат постановки и приемки задач, установить точки тестирования в релизном цикле и научиться приоритизировать задачи по исправлению дефектов.
Формат постановки и приемки задач и дефектов
Способ постановки задачи во многом определяет, насколько быстро и правильно она будет выполнена. Описывать задачи можно по-разному, например, с помощью user stories, которые отражают потребность конечного пользователя системы. Звучит это примерно так: «пользователь хочет получать отчет по нажатию зеленой кнопки».
Минус этого подхода в том, что он не поясняет, что будет «под капотом» у этого решения. User stories оставляют разработчикам слишком много свободы, и иногда это становится проблемой: команда начинает изобретать велосипед или пилит что-то слишком трудоемкое. А учитывая, что в условиях быстрой разработки почти никогда не хватает времени на полноценное документирование, вы при таком подходе получаете загадочный код, сильно затрудняющий интеграцию в продукт новых разработчиков.
Мы обсуждали несколько вариантов оформления задач и дефектов и остановились на «гибридном» подходе: use case + технические подзадачи. Бизнес-заказчик пишет use case, то есть описывает варианты использования нового функционала, а аналитик с тестировщиком на основе этого составляют для разработчиков технически подзадачи. В описании задачи в Jira мы добавляем use case, из которого она сделана, или тест-кейс, позволяющий воспроизвести ошибку, при этом название и описание у основной задачи остается «человекопонятным».
Посмотрим, к примеру, что находится внутри у дефекта с названием «Пользователь не понимает, как обрабатываются ошибки, возникающие при выборе ставки на закупку». В описании задачи находятся:
- кейс, по которому можно воспроизвести ошибку;
- реальный и ожидаемый результат;
- подзадачи для бэкенда и фронтенда с четкими указаниями для разработчиков, что нужно поправить. «Бэкенд: для данного API отдавать на фронтенд соответствующий ответ» + матрица вариантов, показывающая, какие ответы должны быть в каждой из возможных ситуаций. «Фронтенд: для данного API в зависимости от ответа с бэка выдавать соответствующий текст ошибки» + матрица вариантов.
Когда разработчик заканчивает свою подзадачу, он ее просто закрывает. Если все подзадачи закрыты – дефект возвращается на ретест. При обнаружении дополнительных проблем снова создается соответствующая подзадача.
Получается соответствующее правило описания дефектов:
- Создать задачу с описанием функциональной проблемы, кейсом для воспроизведения ошибки и связкой с историей, в рамках проверки которой был найден дефект.
- Добавить к задаче две подзадачи для бэкенда и фронтенда. Подзадачи на фронтенд содержат в себе дополнительно информацию: на какой странице, в какой среде находится дефект, какой API или компонент отрабатывает некорректно, что конкретно надо исправить и ссылку на use case с описанием корректного поведения. Подзадачи на бэкенд содержат в себе описание того, на какой среде найдена ошибка, какой это API, какие параметры передаются, какой приходит ответ, причину, почему реализованная логика считается неверной со ссылкой на документацию, а также указания, что конкретно требуется изменить.
Также мы отказались от формирования AC (acceptance criteria) на нашем продукте, так как на этапе планирования обсуждаем не только то, что разрабатываем и тестируем, но и как.
Что это дало? Такой подход позволил нам в любой момент времени понимать, что не так с функционалом со стороны пользователя, в какой стадии работа над дефектом и в зависимости от нагрузки на бэк и фронт по-разному приоритизировать подзадачи к одному и тому же дефекту.
В итоге еще до начала разработки вся команда понимает, какая часть каждой задачи коснется лично его, а на выходе каждая задача содержит в себе информацию: как разрабатывалась, как тестировалась, есть ли по ней документация, а также что в ней корректировалось в процессе разработки.
Такой подход используется только на нашем продукте, потому что он оказался для нас наиболее удобным. В других продуктах Дирекции больших данных X5 используются свои схемы: например, User stories с AC.
Казалось бы, наш вариант вовсе не способствует ускорению разработки, потому что требует больше шагов, чтобы начать работу. Но это не так.
Мы организовали процесс таким образом, чтобы тестирование велось параллельно с разработкой. Благодаря этому разработчик не сидит без дела, пока тестировщик прорабатывает и максимально локализует задачу. Плюс мы всегда видим, какой конкретно разработчик работал над задачей, как ее реализовывал – это позволяет понимать в будущем, кто из разработчиков быстрее справится с новыми аналогичными проблемами. Логика проста: чем меньше разработчик занимается делами, не связанными напрямую с написанием кода, – тем лучше, а максимально точная локализация дефекта позволяет глубже продумать возможные связки и проблемы, вызванные конкретной ошибкой.
Также может возникнуть вопрос, не мешают ли правила, которые мы установили в нашем продукте, формированию единых стандартов тестирования и разработки в департаменте. На самом деле нет: общие правила департамента определяют, что должна содержать задача к определенной стадии разработки, и мы соответствуем этим требованиям, просто прорабатываем задачу на более ранних стадиях.
Моменты тестирования
Мы долго обсуждали вопрос, на каком же этапе проводить тестирование. Сначала была идея проверять каждую отдельную задачу в локальной ветке, но при таком подходе было бы невозможно проверить, как эти задачи работают вместе, и их конфликты обнаруживались бы только на этапе собранного релиза, когда менять что-либо поздно.
Поэтому мы договорились о тестировании каждой задачи по отдельности, но на одном тестовом стенде. Сначала мы хотели выкатывать несколько задач сразу, но выше я уже рассказывала, какие риски несет в себе эта идея. По одной намного быстрее. Это известный эффект: сокращение количества параллельных задач не замедляет, а наоборот ускоряет процесс. В Канбане, например, есть такая штука, как WIP-лимит (WIP – это work in progress), который ограничивает количество задач, решаемых одновременно каждой ролью.
В итоге мы установили пять точек, где тестировщики активно участвуют в процессе разработки:
- На этапе документации. Следим за тем, чтобы не возникало задач, конфликтующих с логикой того, что уже сделано, фиксируем подробности реализации каждой задачи.
- На этапе постановки задачи. Проговариваем с аналитиком все возможные связанные с задачей кейсы и учитываем их при формировании задачи
- На этапе планирования. Проговариваем, как планируемая реализация может зацепить связанный функционал и какие проблемы может принести. Согласовываем с продактом все критичные дефекты и дополняем спринт.
- На этапе подготовки к релизу. Проверяем итерационно каждую задачу на тестовом стенде, а в день до планируемого релиза собираем все задачи вместе и проверяем на одном стенде.
- После релиза. Проверяем, как релиз работает на проде.
На старте, когда у нас были релизы раз в 2 недели, схема работы выглядела вот так:
Стало (релиз раз в неделю):
Правила взаимодействия связки «бэкенд – тестирование – фронтенд»
Когда в API между бэкендом и фронтендом пересылается много разных данных, не всегда понятно, для чего они нужны и как взаимодействуют. Из-за этого на фронтенде могут происходить поломки. Например, с бэка передается номер калькуляции, demand cal. Номинально это один параметр, но для осуществления расчета вместе с ним с бэка должно «притягиваться» еще восемь полей. Если не передать их вместе с номером калькуляции, на фронтенде эта операция не выполнится.
Чтобы избежать таких ситуаций, мы стали описывать передаваемые параметры, указывая их в комментариях к подзадаче на разработку API в Jira, где объяснялось, какими данными будут обмениваться бэк и фронт. Пробовали вести описания всех API в фреймворке Swagger, но с его помощью при автоматическом формировании документации не получалось передать фронтенду, что именно бэк будет делать с переданными параметрами. Поэтому мы договорились, что, если речь о параметре, который не просто записывается на бэке, а использует другие параметры, необходимо описывать его назначение в задаче.
Также мы стали контролировать обозначение переменных, чтобы в однотипных API все поля были стандартизованы. Наш продукт состоит из микросервисов, и в каждом могут использоваться свои названия полей. В одном поле с названием поставщика может быть supplier, в другом – supplierID, в третьем name и т.д. При передаче этих данных в один компонент фронтенда могут начаться сложности, поэтому мы прошлись по всем параметрам и начали стандартизировать все названия переменных. Для этого собрали сводную таблицу всех текущих обозначений, таблицу всех компонентов фронта и используемые ими переменные (с чем сильно помог фронтенд-разработчик) и сверили их. Теперь все новые API получают стандартные названия переменных, а старые API правятся при возникновении задач на их доработку.
Ускорение работы по исправлению дефектов
На этапе постановки задачи приоритеты определяет бизнес-заказчик – ему виднее, что и в каком порядке нужно для развития продукта. Но после выкатки на dev, когда появляются задачи на исправление дефектов, их приоритетами командует тестировщик.
Иногда возникает необходимость срочно поменять приоритеты этих задач – например, мы обнаруживаем мелкий дефект на бэке, без исправления которого не может начать исправления команда фронтенда.
Раньше в таких ситуациях мы сразу шли к разработчикам и просили их поменять приоритет задач, но это их отвлекало. Поэтому мы договорились, что будем обращаться только в определенные моменты – после code freeze, до 5 раз в день. Что это дало? Мы перестали снижать продуктивность разработчиков внезапными обращениями, избавились от простоев, увеличили время для проработки задач аналитиком.
Более того, благодаря тому, что задачи теперь не появляются у разработчиков стихийно, мы всегда знаем, у кого какая загрузка, кто раньше работал над задачей и сможет быстрее с ней справиться. В результате намного лучше понимаем, успеем ли мы подготовить релиз по графику или нет.
Эти меры вместе с единой логикой выкатки кода на dev, релиз и прод позволили сократить период исправления дефектов с 3 дней до 3-4 часов.
Результаты
За 9 месяцев работы нашего продукта «Автоматизация закупок» у нас получилось сократить релизный цикл с 2,5 недель до 1 недели с возможностью ежедневной выкатки, значительно повысив стабильность релизов.
Что изменилось:
- Мы избавились от необходимости исправлять дефекты после разработки, так как по максимуму вынесли эту работу на этап подготовки задач.
- Сократили период исправления дефектов с 3 дней до 3-4 часов.
- Получили возможность выкатывать релизы «по команде». Теперь можем в любой день собраться, выкатить задачи, и к вечеру все будет готово и отлажено.
- Повысили прозрачность процессов для всех участников процесса: теперь все разработчики и тестировщики команды понимают, что происходит в данный момент, кто какими задачами занят, сколько еще времени нужно на разработку и исправление ошибок и т.д.
BONUS: удалось снизить уровень стресса в команде (я надеюсь), а еще благодаря согласованной работе команды (спасибо деливери) без проблем перейти на удаленку :-)
Внедряя эти улучшения, мы придерживались нескольких правил:
- Тестировщики и разработчики – в одной лодке (повторять это как мантру!), поэтому первое, что нужно сделать тестировщику – поладить с командой и узнать, что беспокоит ее больше всего, заручиться ее поддержкой. Моими союзниками и партнерами в команде стали деливери-менеджер и разработчики.
- Готового идеального решения нет, и его нужно искать. Тестировщик никому не навязывает свои правила, он подстраивается под команду и меняет свои подходы вместе с ней, держа при этом в голове образ светлого будущего и мягко внедряя меры для его достижения)).
- Слишком жесткие ограничения и стандартизация – не метод. Если переборщить, команды могут потерять гибкость.
Правила взаимодействия, которые помогли нам ускорить развитие этого продукта, нельзя в чистом виде перенести на другие продукты Дирекции – они устроены иначе, и потребности разработчиков там отличаются. Но принцип создания этих правил будет таким же: устанавливать порядок выкладки кода, находить оптимальные точки для тестирования, документировать код и API.
Параллельно с работой внутри продуктов мы вырабатываем правила, которые призваны облегчить взаимодействие между продуктами, и об этом мы обязательно расскажем в следующих материалах. Так в Дирекции больших данных постепенно формируется стратегия развития качества продуктов.