Обеспечение качества на всём пайплайне разработки, или как создавать продукты, отвечающие ожиданиям
Командная работа при разработке программного обеспечения (ПО) — это не только объединение компетенций и экспертиз, но и общая ответственность за конечный продукт. К сожалению, об этом часто забывают, оставляя проверку качества и соответствие требованиям только на QA-инженеров. Это ошибочная практика, которая нередко заканчивается выкаткой в прод «сырых» продуктов с недочетами и уязвимостями.
С вами снова Алексей Петров, директор по качеству в Одноклассниках. В этой статье я расскажу, как команда может на каждом этапе разработки ПО заботиться о качестве будущего продукта, а также бороться с багами еще до их появления.
Материал подготовлен по мотивам моего доклада на CodeFest. Вы можете посмотреть его здесь.
Небольшой пролог
Академические формулировки гласят, что качество — это степень соответствия совокупности присущих характеристик объекта требованиям. Если проще: чем качественнее продукт, тем больше он соответствует запросам конечного пользователя.
В условиях современного рынка, качество — одно из ключевых конкурентных преимуществ продукта и компании. Это очевидная взаимосвязь, поэтому множество команд разработки ПО озабочены обеспечением качества и используют для этого разные практики вроде Shift-left/right testing и других.
Вместе с тем, во многих командах по-прежнему встречаются ситуации, когда задачи обеспечения качества трактуют неверно:
оставляют их исключительно на QA-инженера (специалиста по обеспечению качества);
позволяют каждому специалисту иметь свои, независимые приоритеты, которые могут не согласовываться с целями других участников.
И в первом, и во втором случае обеспечить высокое качество продукта, а также предупредить появление проблем или багов практически нереально.
Поэтому перед внедрением любых практик, направленных на улучшение разрабатываемого продукта, важно сделать качество общей целью, а его достижение — общей задачей. Причем, при соблюдении best practice, каждый из команды (product owner, разработчик, QA-инженер) сможет повышать качество «на местах», реализуя комплексный подход.
Best practice для ключевых этапов жизненного цикла ПО
Выделим основные этапы жизненного цикла разработки (Software Development Lifecycle, SDLC):
На каждом из этих этапов можно реализовывать меры, направленные на обеспечение качества. Рассмотрим подробнее, какие практики можно применять.
Требования
Разработка ТЗ
Техническое задание на разработку — исходный документ, без которого невозможен старт работы над продуктом в целом. Но важно понимать, что из простого документа, подготовленного «на скорую руку» сложно получить качественный проект: описанные в техническом задании требования должны стать фундаментом качества будущего ПО.
Поэтому к подготовке ТЗ надо подходить основательно. В идеале максимально подробно описывать желаемый результат и функционал — это важно, чтобы исключить разночтения специалистами во время разработки и тестов.
Безусловно, на разработку детального и качественного ТЗ надо много времени и ресурсов, но без внятного ТЗ результат неочевиден. Лучше сразу сделать правильное ТЗ, чем потом переделывать уже готовую реализацию с нуля.
Актуализация ТЗ по всему SDLC
Написать ТЗ — недостаточно. При разработке исходные требования могут меняться. Например, если окажется, что реализовывать ту или иную фичу неоправданно сложно или дорого. Или если появятся новые требования.
Именно поэтому, чтобы исключить ситуации, при которых продукт, попадающий на тестирование, не будет соответствовать изначальным требованиям, ТЗ важно регулярно проверять и актуализировать.
При этом важно, чтобы в команде был назначен один ответственный за актуализацию специалист — это нужно, чтобы правки в ТЗ вносились централизованно, только после согласования с заказчиком разработки, а не на личное усмотрение исполнителей на местах.
3 Амиго
3 Амиго — практика синхронизации работы при разработке ПО на разных этапах. Метод подразумевает проведение разработчиком, тестировщиком и продактом встречи, в ходе которой обсуждают видение реализации проекта и стараются устранить пробелы в том, как понимаются потребности бизнеса и чего ожидают клиенты.
Нередко всё сводится не только к обсуждению задачи, но и к ответам на вопрос: «а что будет, если…». И чем больше конкретных, «неудобных» вопросов прорабатывается, тем меньше неочевидных проблем может «всплыть» в готовом продукте. Тут всё просто: обнаружение потенциальных узких мест в реализации продукта на этапе формирования ТЗ чревато всего лишь необходимостью добавить несколько строчек в файл с требованиями. А обнаружение этих же проблем уже в момент разработки неизбежно обернется необходимостью править код или делать откаты, что скажется не только на общем качестве, но и на увеличении time-to-market.
Таким образом, совместная проработка требований участниками команды дает комплексную оценку предстоящей задачи еще задолго до начала реализации.
Первичный список проверок (QA Checklist)
На этапе подготовки ТЗ также можно составить предварительный перечень проверок, которые будет проходить продукт. В идеале, если в формировании списка таких проверок примут участие все вовлеченные специалисты: product owner, разработчик, QA-инженер. Командная работа в данном случае позволит исходно подсветить все критически значимые места в будущем продукте.
Одновременно с этим, такой чек-лист, прикрепленный к задаче, может дать разработчику и тестировщику примерное представление о предстоящем тестировании и приемке функционала.
Разработка
Unit-тесты
Unit-тесты (или модульные тесты) — метод тестирования ПО, который подразумевает проверку работоспособности отдельных функциональных модулей, процессов или частей кода продукта. То есть цель Unit-тестов — показать, что по отдельности новые части ПО работоспособны.
Unit-тесты лежат в основе пирамиды тестирования. Они легкие и быстрые, вместе с тем, дают понимание уровня покрытия кода тестами и позволяют избавиться от многих неочевидных проблем и ошибок на самых ранних этапах разработки (еще до попадания на этап полноценного тестирования).
Code-review
Code-review — практика, при которой разработчики смотрят и оценивают код, написанный коллегами. Вычитка кода дает возможность не только найти ошибки раньше, но и увидеть скрытые дефекты, к которым может привести неоптимальное решение.
Надо понимать, что, работая вместе над изучением кода, каждый член команды может предложить более разумные решения, которые могут улучшить конечный продукт. То есть, кроме нахождения ошибок, эта практика помогает и в поиске лучшей реализации проекта.
Примечание: Для проведения Code-review можно привлекать не только разработчиков, но и тестировщиков (при достаточном уровне экспертизы), а также использовать специальные инструменты — например, статические анализаторы кода и даже алгоритмы ИИ.
Pipeline с ограничениями
Один из способов раннего обеспечения качества разрабатываемого ПО — выстраивание пайплайна с ограничениями. То есть, если код не удовлетворяет конкретным требованиям, его дальнейшее продвижение по пайплайну будет невозможным. Это нужно, чтобы исключить ситуации, при которых проверки качества или соответствия требованиям игнорируются умышленно или ошибочно пропускаются. Например, ограничения могут срабатывать, если:
код не прошел обработку линтерами;
нет автотестов или их результаты неудовлетворительны;
не выполнены дополнительные скрипты.
Фактически «триггер» можно выбрать любым в рамках собственной реализации с учетом всех ее особенностей. Главное — чтобы код низкого качества с потенциальными проблемами не попал в прод. Например, у нас в ОК в прод допускается только выкатка фич, у которых все тесты зелёные.
QA Notes
В виде дополнительной практики, помогающей обеспечивать и поддерживать высокое качество разрабатываемых продуктов, можно сделать обязательным составление QA Notes.
QA Notes — это заметки от разработчиков, которые оставляются при передаче задачи в тестирование. В них они могут подсветить риски, дополнительные сценарии тестирования, а также перечислить условия, необходимые для проведения тестов.
Надо понимать, что QA Notes — рекомендация, а не строгое руководство к действию. Вместе с тем, такой документ важен, чтобы превентивно уведомить тестировщика о пуле неочевидных задач и нюансов. Например, если внедренная фича затрагивает и сторонние, уже работающие библиотеки, то в QA Notes можно подсветить, что надо проверить не только новый, но и существующий функционал. То есть практика полезная, но для ее внедрения надо, чтобы разработчик понимал архитектуру ПО и логику выстроенных зависимостей.
Тестирование
Публичный список проверок
Нередко после проверок тестировщики не оставляют никаких детальных артефактов о проделанной работе. Поэтому разработчикам сложно понять, что именно проверялось и в каком объеме, как прошли проверки и достаточно ли их. В том числе не всегда очевидно, придерживался ли тестировщик рекомендаций, упомянутых, например, в QA Notes или QA Checklist. Потенциально это может сказаться на качестве продукта — например, если впоследствии окажется, что имеющихся проверок недостаточно, а этого никто не заметил раньше.
Чтобы исключить такие риски, желательно создавать публичный список проверок — документ, в котором тестировщик будет подсвечивать, что именно и как именно он будет тестировать или протестировал. Таким образом, с помощью такого чек-листа вся команда сможет:
оценить объем, глубину и качество проверок;
внести правки в тестовые сценарии;
сократить или расширить список проверок.
Ведение такого публичного чек-листа фактически дает двойной профит:
тестирование становится прозрачным, команда может повлиять на его проведение;
тестировщик получает основу для отчета по тестированию.
Приёмочные тесты
Приёмочные тесты — базовые проверки проделанной работы, которые помогают убедиться в том, что ПО соответствует ключевым требованиям. Фактически приёмочный тест часто сводится к проверке продукта заказчиком (например, продактом) — чтобы убедиться, что разработчик правильно понял задачу и реализация удовлетворяет исходным требованиям. Одно из ключевых преимуществ таких тестов в их простоте — для проверки достаточно вовлеченности разработчика и заказчика.
Командное тестирование
Командное тестирование — подход, при котором к проведению тестов привлекается вся команда. Такая практика полезна сразу по ряду причин:
помогает шарить экспертизу в тестировании внутри команды;
снимает с QA-инженера эффект бутылочного горлышка;
позволяет всем «исполнителям» дополнительно проверить свою работу на наличие багов и ошибок;
дает возможность глубже разобраться в архитектуре и зависимостях решения.
Польза практики и в том, что она потенциально может изменить подход к разработке в целом. Например, если продакт увидит во время теста, что есть баг, который появился из-за недостаточно подробно составленного ТЗ, или если разработчик поймет, что в продукт попала ошибка, которую можно было поймать раньше, если не игнорировать код-ревью. В итоге каждый может подсветить свои слабые места и в дальнейшем уделять им больше внимания.
Интеграционные и регрессионные тесты
Интеграционные тесты — проверки, которые позволяют убедиться, что все взаимодействия с созданным ПО отвечают требованиям, а новые фичи работают правильно, предсказуемо и без проблем.
Регрессионные тесты — проверки, которые проводятся после внесения изменений, исправления ошибок или обновлений. Они дают информацию о работоспособности ранее существовавшего функционала и позволяют убедиться, что любые изменения не приводят к деградации качества ПО, не влияют на существующую функциональность и не создают новых проблем.
Автоматизированные тесты
Автоматизация тестов — распространённая практика, которую часто рассматривают как способ ускорения проведения тестов и сокращения привлечения тестировщиков к однотипным рутинным проверкам. Помимо этого, они также являются эффективным способом улавливания ошибок, поскольку дают возможность снизить влияние человеческого фактора и связанных с ним рисков.
Тут надо отметить один нюанс. Автотесты — это круто. Поэтому команды нередко стараются автоматизировать все тесты, до которых «дотягиваются руки». Но надо понимать, что не стоит пытаться безосновательно автоматизировать всё — в отдельных случаях затраты на разработку автотестов будут кратно выше, чем польза от их внедрения.
Отчёт по тестированию
Отчёт по тестированию — документ, в котором тестировщик подробно расписывает проведенные проверки и их результаты. Причем отчёт может содержать не только текст, но и таблицы, списки, графики, описание тестируемых конфигураций, используемого стека и не только. Основой для такого отчёта может быть упомянутый ранее публичный список проверок.
Помимо отслеживания работы тестировщиков, отчёты нужны и для аргументированного принятия решения по поводу судьбы проверяемого ПО — можно его катить в прод или надо возвращать разработчику и дорабатывать.
Более того, отчёт по тестированию обязательно нужен на случай разбора инцидентов, если ПО всё же попало в прод, но дало просадку метрик, начало влиять на уже имеющиеся модули приложения или работает неправильно. В таких ситуациях наличие отчёта по тестированию может помочь в локализации причин возникновения нештатной ситуации.
Эксплуатация
Приёмочные тесты в проде
Приёмочные тесты — один из завершающих этапов тестирования, на котором ПО до релиза на всю аудиторию проверяется на приемлемость, готовность и качество. Цель приёмочных тестов — понять, насколько продукт решает задачи бизнеса и соответствует запросам пользователей. Есть несколько основных типов приёмочных тестов.
Пользовательское приемочное тестирование (User Acceptance Testing, UAT). Проводится, чтобы понять, соответствует ли ПО требованиям пользователей.
Эксплуатационное приемочное тестирование (Operational Acceptance Testing, OAT). Проводится, чтобы проверить основные параметры, в том числе уровень отказоустойчивости, технической и информационной безопасности.
Альфа-тестирование (Alpha Testing). Выполняется, чтобы проверить еще «сырой» продукт на соответствие ТЗ и пользовательские сценарии в нем.
Бета-тестирование (Beta Testing). Подразумевает проверку уже готового продукта на наличие невыявленных или неочевидных недоработок. К бета-тестам обычно привлекают реальных пользователей, которые в рамках теста могут полноценно использовать доступный функционал ПО и выявлять в нем баги, присущие только продовой нагрузке.
Выбор типа приёмочных тестов обычно зависит от исходных требований и доступных тестовых сред (которые обычно надо дополнительно развертывать). Но в идеале сочетать сразу несколько подходов, даже несмотря на возможные издержки — лучше инвестировать в тесты до релиза, чем после тратить деньги и время на доработку в авральном темпе проблемного ПО, попавшего в прод.
Канареечная выгрузка
Канареечная выгрузка (canary release) — стратегия развёртывания новой версии ПО для последующего тестирования. Метод подразумевает, что текущая версия остаётся основной в проде, а новая используется только в отдельных сценариях. Такой подход позволяет получить информацию о качестве нового ПО или его отдельной фичи, прежде чем выпускать её на всю аудиторию.
Примечательно, что канареечная выгрузка, кроме очевидных проблем, также позволяет безопасно выявить просадки по перформансу. А также, если после выкатки новой функции пользователи стали меньше пользоваться обновленным сервисом — проблема может быть не только в багах на уровне кода, но и в недостатках со стороны UX/UI.
Blue/Green развёртывание
Blue/Green развёртывание — подход к релизу и тестированию обновлений, который подразумевает использование двух полностью независимых окружений. Так:
в синем («Blue») продолжает крутиться прод с пользовательской нагрузкой;
в зелёное («Green») релизятся обновления, на которые перенаправляется часть органического трафика с целью тестирования на реальных пользователях.
Дальше алгоритм прост:
по мере проверки релиза на части аудитории, объем трафика на «зелёное» окружение увеличивается;
после успешного завершения всех тестов и пользовательских сценариев трафик полностью переключается на «зелёное» окружение.
Таким образом, можно последовательно проверять части нового ПО на соответствие требованиям качества и пускать в прод на всю аудиторию только то, в чем команда полностью уверена.
Важно, что подход позволяет обеспечить безопасную бесперебойность обновлений (как вперед, так и назад). Так, если в «зелёном» окружении выявляются глобальные проблемы, можно быстро откатиться к прошлой версии, просто переключив маршрутизацию на «синее» окружение.
Пользовательская документация
С пользовательской документацией всё несколько иначе, чем в вышеупомянутых практиках. Зачастую она нужна не для того, чтобы повысить качество продукта, а для того, чтобы конечные пользователи понимали, что именно считается корректной работой.
Особенно она важна в случае запуска новых проектов или после глобальных обновлений. Например, если после обновления пользователи не увидят кнопку на привычном месте или столкнутся с новыми правилами авторизации, они могут расценить это как ошибку и начать заваливать техподдержку обращениями или распространять на внешних площадках информацию о неправильной работе ПО, нанося ущерб репутации компании.
Таким образом, пользовательская документация:
упрощает работу с ПО для конечного пользователя;
является точкой истины для общения команд разработки и техподдержки с пользователями.
Вместе с тем, надо понимать, что:
на создание технической документации надо выделить ресурсы команды;
важно позаботиться о предоставлении удобного доступа к пользовательской документации;
пользовательскую документацию важно постоянно актуализировать.
Техническая поддержка
Техническая поддержка — неочевидный, но эффективный способ улучшения продукта и поддержания его качества на высоком уровне. Всё потому, что техподдержка позволяет получить полноценную, развернутую обратную связь от конечных пользователей, в том числе:
информацию о качестве ПО;
данные о дефектах и сбоях;
запросы на улучшение функционала.
Но для получения профита от техподдержки, надо обеспечить прозрачный процесс взаимодействия с ТП и выстроить работающий механизм эскалации пользовательских обращений, чтобы обратная связь и запросы не собирались бесцельно.
Разбор инцидентов
Разбор инцидентов — это не только «боль и страдания» для команды, нацеленные на устранение инцидентов и причин их появления. Это также способ превратить проблемы в возможности для совершенствования. Обусловлено это тем, что правильный разбор проблем и работа над ошибками помогают застраховаться от рецидивов в будущем, то есть повысить качество продукта на долгосрочную перспективу.
Но, как и в предыдущих случаях, чтобы эта практика приносила результат, команде важно закладывать ресурсы на воплощение в жизнь action items по результатам проводимых разборов.
Анализ технических и продуктовых метрик
Технические метрики позволяют получить представление о работе ПО в промышленной эксплуатации с технической стороны и вовремя реагировать на инциденты.
В свою очередь, продуктовые метрики позволяют получить представление о работе ПО в проде с бизнесовой, продуктовой стороны и также реагировать на изменение паттернов и отклонение от привычных показателей. Например, если до выкатки обновлений пользователи отправляли по 10 миллионов событий в минуту, а после выпуска обновления показатель снизился до 6 миллионов, то это может быть не только неудачным экспериментом, но и следствием возникающей у пользователей технической ошибки.
Таким образом, анализ технических и продуктовых метрик — это способ не превентивного выявления проблем, а метод их быстрого обнаружения уже в проде для устранения дефектов.
Что в итоге
Есть много эффективных практик, которые помогают обеспечить качество ПО на всех этапах жизненного цикла — от составления ТЗ и разработки до эксплуатации в проде. Вместе с тем, надо понимать, что обеспечение качества — это не процедура, а непрерывный процесс. В идеале он должен сводиться к циклу Деминга (PDCA: Plan, Do, Check, Act) — такой подход позволит постоянно повышать уровень требований и качества продуктов.
Причем о мерах повышения качества и способах устранения проблем лучше начать думать еще на стадии формирования идеи — согласно кривой Боэма, чем раньше выявлен дефект, тем дешевле его исправление.
Поэтому важно, чтобы в процессы улучшения качества была вовлечена вся команда, и каждый специалист понимал свою ответственность и «зоны роста», на которые он может повлиять. Причем каждая из практик лучше работает в комбинации. Поэтому, чем больше методик улучшения применено, тем лучше будет результат.
Отдельно стоит отметить, что «доработки ради доработок» — заведомо провальная история. Изменения должны быть измеряемыми — так вы сможете не только четко поставить перед собой цель, но и точно понять, каких результатов удалось достичь.