Feature flags и A/B-эксперименты: выкатывать безопасно и измерять

Продукт5 мин чтения
  • #feature-flags
  • #ab-testing
  • #release
  • #experimentation

Feature flags (флаги возможностей) — простая идея с большими последствиями: вы отделяете момент, когда код попадает на продакшен (деплой), от момента, когда он начинает работать для пользователей (включение фичи). Это меняет модель релизов. Раньше релиз = выпустить код = дать его всем пользователям сразу, с риском. С флагами релиз становится управляемым: код живёт на проде, но выключен, и вы решаете — кому, когда и в каком объёме его показывать.

Что это даёт

Kill switch — мгновенное выключение

Если новая фича вызвала проблемы, не надо делать отката деплоя (redeploy занимает минуты и тащит за собой хаос). Достаточно переключить флаг в false — и фича выключается за секунды, без изменения кода. В high-stakes среде (e-commerce в чёрную пятницу, финтех) kill switch — это страховка, которая окупает всё внедрение.

Канареечный релиз

Включить фичу на 1% трафика, посмотреть на метрики (ошибки, latency, конверсия), затем расширить до 5%, 10%, 100%. Если на 5% что-то пошло не так — откатили, не успев навредить большинству. Классическая альтернатива — «выкатить на всех и молиться», и она до сих пор встречается чаще, чем хотелось бы.

A/B-эксперименты

Случайно разделить пользователей на две группы: контрольная видит старую версию (флаг off), экспериментальная — новую (флаг on). Измерить разницу в целевой метрике (конверсия, retention, средний чек). Если новая версия значимо лучше — раскатать на всех. Если хуже — откатить. Это основа data-driven разработки: решения принимаются по данным, а не по интуиции.

Бета для части пользователей

Включить фичу только для пользователей с флагом beta-tester — ранний доступ для добровольцев, сотрудников, конкретных клиентов. Получить обратную связь до полного релиза.

Релиз по подписке

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

Категории флагов

Не все флаги одинаковые, и важно их различать — у них разный жизненный цикл.

Release-флаги. Короткоживущие, пока фича раскатывается. Когда rollout достиг 100% и фича стабильна — флаг удаляется, а мёртвая ветка кода старого поведения выкидывается. Жизненный цикл: дни–недели.

Experiment-флаги. Привязаны к A/B-тесту. Живут, пока идёт эксперимент и собирается статистика. После завершения — либо раскатываются как release-флаги, либо удаляются.

Ops-флагы. Долгоживущие kill switch для критичных операций. Например, флаг «выключить тяжёлый экспорт в CSV, если БД перегружена». Живут месяцами или постоянно.

Permission-флаги. Привязаны к роли или подписке пользователя. Это часть бизнес-логики продукта (premium-фичи), а не инструмент релиза. Самые долгоживущие.

Смешивать эти категории в одном хранилище и одном процессе управления — частая путаница. Permission-флагам нужна_audit и BC-стратегия, release-флагам — expiration.

Что выбрать

Рынок зрелый, варианты есть.

SaaS-решения

LaunchDarkly, ConfigCat, Flagsmith Cloud, Split. Быстро стартуют (подключили SDK), богатый UI для управления флагами, аудит-лог, таргетинг по сегментам, A/B-эксперименты из коробки.

Плюсы: время до внедрения — часы, не недели; не надо поддерживать инфраструктуру; аналитика экспериментов готовая.

Минусы: стоимость растёт с числом флагов/пользователей/запросов (биллинг часто по MAU или по числу eval-запросов); внешняя зависимость в критическом пути — если SaaS лёг, флаги у вас в кэше, но обновить без него нельзя.

Open-source / self-hosted

Unleash, Flagsmith, AppToggles. Разворачиваются в собственной инфраструктуре, нет vendor lock-in, данные остаются у вас.

Плюсы: контроль, нет зависимости от внешнего сервиса, нет платы за объём.

Минусы: сами поддерживаем, сами настраиваем отказоустойчивость, сами делаем UI и аналитику (включено в фичи продукта, но надо разворачивать).

Своя реализация

Соблазн написать «простую таблицу в БД с флагами». На первый взгляд — пара дней работы. На практике легко недооценить:

  • Кеширование на стороне клиента. Если каждое приложение при каждом eval ходит в БД за флагом — это лишний round-trip на каждый запрос. Нужно кеширование с инвалиадацией.
  • Консистентность между сервисами. Если один сервис видит флаг on, а другой — off (из-за кешей) — поведение рассинхронизируется.
  • Аудит. Кто, когда и зачем включил/выключил флаг — без этого невозможно расследовать инциденты.
  • Rollout-проценты. Случайное распределение по пользователям с устойчивостью (один и тот же пользователь всегда в одной группе) — не тривиально.
  • Таргетинг по сегментам. «Только premium-пользователи из РФ» — без UI это превращается в ад из конфигов.

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

Главный риск — технический долг флагов

Это оборотная сторона, о которой молчат продающие презентации. Флаги — это if в коде. Когда флагов становится много, а дисциплина их удаления слабая, кодовая база превращается в лабиринт ветвей:

def process_order(order):
    if feature_flags.new_tax_logic:
        if feature_flags.eu_vat_override and order.country == 'DE':
            ...
        else:
            ...
    else:
        # старая логика, которая уже год как не нужна
        ...
    if featureFlags.legacy_2024_promo:  # промо закончилось в декабре 2024
        ...

Через два года в коде десятки мёртвых веток, никто не помнит, что они делают, удалить страшно — вдруг кто-то ещё переключит. Тестировать надо все комбинации флагов (экспоненциальный рост).

Дисциплина против этого:

  • Expiration-дата на release-флагах. Каждый release-флаг при создании имеет срок жизни (2 недели, месяц). По истечении — флаг удаляется, мёртвая ветка выкидывается.
  • Регулярный аудит. Раз в квартал — смотреть все долгоживущие флаги и выяснять, нужны ли они.
  • Удаление старой ветки сразу после полного rollout. Достигли 100% — следущая задача в спринте: убрать if flag и оставить только новый код.
  • Максимально короткий жизненный цикл release-флагов. Чем дольше живёт флаг, тем больше кода вокруг него обрастает, тем сложнее выкинуть.

Короткое summary

Feature flags — это разделение деплоя (код на проде) и релиза (код работает для пользователей), меняющее модель выкатки. Дают kill switch (выключить за секунды без redeploy), канареечные релизы (1% → 5% → 100%), A/B-эксперименты, бета-доступ и релиз по подписке. Четыре категории флагов с разным жизненным циклом: release (короткие), experiment (пока идёт тест), ops (kill switch, долгие), permission (бизнес-логика, постоянные). Выбор инструмента: SaaS (LaunchDarkly, ConfigCat) — быстро, но дорого и зависимость; open-source (Unleash, Flagsmith) — контроль, но сами поддерживаем; своя реализация — соблазн, но легко недооценить (кеш, консистентность, аудит, rollout-проценты). Главный риск — технический долг флагов: мёртвые if-ветки копятся, если нет дисциплины удаления. Лекарство: expiration-даты, регулярный аудит, удаление старой ветки сразу после 100% rollout.

Что почитать