13/09/2022

Как запустить DevOps-конвейер на полную мощность

У нас в Газпромбанке сложилась довольно интересная ситуация. Банк относительно недавно начал активно работать с розницей, которая как локомотив начала тянуть все внутрибанковское IT и менять характер работы всех подразделений.

Одна из главных наших проблем (впрочем, как и у многих) — долгие релизы, низкое качество кода, недоступность и нестабильность систем на тестовых полигонах. Но главное — интеграционные релизы. Когда несколько команд одновременно пытаются зарелизить свои доработки, нужно много времени и средств, чтобы синхронизировать всех. При этом каждый привносит новые баги, все начинают бегать кругами, спотыкаться, фиксить, перенакатывать… В итоге качество продукта низкое, а пользователь смотрит на это все с недоумением.

Как с этим всем бороться? Мы пришли к такому рецепту: избавиться от интеграционных релизов. Вообще. Собрать автономные, кросс-функциональные команды, каждая из которых будет выполнять свою задачу, не толкаясь локтями с другими. Для этого перепилить пайплайн, повысить инженерную культуру, ввести стандарты и так далее. Подробнее — под катом.

Для начала мы обратили внимание на то, как у нас устроено тестирование. О том, как и в каком порядке должны быть сгруппированы тесты написал еще Майк Кон в книге «Scrum: гибкая разработка ПО» (Succeeding With Agile. Software Development Using Scrum). Он предложил хорошую абстракцию: пирамиду тестирования. Она в простом и понятном виде демонстрирует как правильно должен быть организован процесс разработки.

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

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

Quality Gates

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

Для начала «включили» Quality Gate на покрытие юнит-тестами в каждой системе и в каждом сервисе, которые используют наш пайплайн. Нужно было чтобы каждая команда по мере развития своего продукта на регулярной основе пилила «юниты». Их создание должно войти в привычку, как чистка зубов по утрам.

Если вы еще этот этап не прошли, готовьтесь — будет много БОЛИ. Всем некогда, всем надо срочно, быстро и вот прямо сейчас, а тесты мешают. Но результат стоит того. Уже через месяц аналитика показала, что количество функциональных дефектов на этапе тестирования снизилось вдвое. Да, срез пока довольно маленький: покрытие тестами розничных продуктов пока около 40%, но мы планомерно идем к увеличению покрытия.

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

Вторые «ворота» ориентированы непосредственно на процесс деплоя. Они включает в себя базовые проверки кода на жизнеспособность — Health Check. А после этого, в зависимости от того, какие ресурсы есть у команды, прогоняются ручные и автоматизированные тесты.

Версионирование

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

Этот стандарт описывает обязательства, которых надо придерживаться при реализации взаимодействия сервисов и команд между собой. Если сформулировать совсем коротко: сохраняйте обратную совместимость при изменении сервисов.

Номера версий должны четко соответствовать стандарту. Чтобы соблюдать SemVer-правила, перед деплоем в Nexus это соответствие дополнительно проверяется скриптами (на Python). Ничего задеплоить не выйдет до тех пор, пока все не будет по правилам.

Номера версий должны четко соответствовать стандарту. Чтобы соблюдать SemVer-правила, перед деплоем это соответствие дополнительно проверяется скриптами (на Python). Ничего задеплоить не выйдет до тех пор, пока все не будет по правилам.

Что бывает если на это забить? Некая компания выпускает минорный апдейт некоего продукта. Некий разработчик смотрит на набор фичей, читает описание релиза и решает, что все это ему надо. Ставит обновление. Все падает. Начинается головная боль: надо разобраться что произошло, пофиксить, откатить все обратно, предпринять меры, чтобы такое не повторилось. В зависимости от того, что именно обновлялось и как именно упало, голова может болеть от месяца до полугода.

Тут можно вспомнить Apple. Компания любит своих пользователей, любит продавать им крутые продукты, но при этом совершенно ненавидит разработчиков. Когда выходят обновления инструментов, iOS и MacOS, то каждый раз (по нескольку раз за год) ломается основная среда разработки — Xcode. Даже после минорных обновлений производство может встать из-за того, что приложения перестают собираться.

Feature Toggle

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

Плюс к этому, разработку можно вести более гибко: когда несколько команд работают над какой-то фичей, то часть каждой можно выкатывать в прод в выключенном состоянии. После того как соберутся все куски, фичу можно либо сразу включить, либо допатчить перед этим в (опять же в нерабочем состоянии).

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

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

Последний тип тоглов — A/B-тесты — самый интересный с точки зрения бизнеса. С их помощью можно создать несколько вариантов одной фичи и раскатать каждый на определенную группу/количество пользователей. А затем посмотреть, какой принес большую конверсию и в автоматическом режиме выпустить его уже на всех.

API First и контрактное тестирование

Перед тем, как писать код, нужно заключить контракт (используем стандарт OpenApi 3.0 и AsyncAPI) с тем, с кем хотим интегрироваться. В контракте прописываем спецификации, версионируем, фиксируем с потребителем и отдаем в разработку. А затем используем автоматизированные контрактные тесты, которые проверяют соответствие описания и реализации определенного контракта. По сути, это набор регрессионных тестов, с помощью которых мы можем отследить отклонение от контракта на раннем этапе. В итоге все, что не соответствует спецификациям, не пролезет в Quality Gate.

Много тестовых полигонов не нужно

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

При этом мало кого волнуют проблемы обновления этих полигонов, поддержания их в актуальном состоянии и обеспечения доступности. Масштабирование — простой выход, но выход в никуда. Такой подход приведет не к решению проблем, а к их преумножению (помните про контроль версий?).

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

DORA-метрики

Чтобы понять, к чему приводят наши усилия, мы используем DORA-метрики, которые позволяют оценить качество процессов разработки и эксплуатации продуктов. Собственно, вот они:

1. Время внесения изменений (Lead Time for Changes). Промежуток времени между изменением кода и появлением изменений в проме. Эффективные команды обычно измеряют его в часах.

2. Частота развертывания (Deployment Frequency). Показывает как часто команда выпускает новые фичи на пром. В идеале изменения должны развертываться on-demand несколько раз в день.

3. Частота сбоев при внесении изменений (Change Failure Rate). Процент изменений кода, требующих быстрого исправления или устранения других недостатков после развертывания в рабочей среде. В идеальном мире — от 0 до 15%.

4. Время, которое требуется на восстановление после частичного перебоя в обслуживании или полного отказа (Time to Restore Service). Высокоэффективные команды быстро восстанавливаются после сбоев системы, тогда как менее результативным может потребоваться неделя.

Тут, честно говоря, мы пока отстаем. Если принять работу команд, выкатывающие новые фичи по нескольку раз в день за 100, а тех, кто релизит раз в два месяца за 0, то нашу эффективность по DORA можно приблизительно оценить на 45. Сейчас наша цель не только прийти on-demand-релизам, но и максимально догнать лидеров.

Подытоживая. Нельзя сказать, что мы придумали что-то новое. Все инструменты и подходы хорошо и давно известны. Нужно только собраться, переломить сопротивление внутри команд и организовать разработку в соответствии с правилами. Результаты станут видны практически сразу.


Читайте эту и другие статьи об IT в Газпромбанке в нашем блоге на Хабре.

Другие статьи по теме
0%

Банк ГПБ (АО) использует файлы cookie. Подробная информация –
в правилах по обработке персональных данных. Вы можете запретить сохранение cookie в настройках своего браузера.