Feature flags и A/B-эксперименты: выкатывать безопасно и измерять
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.
Что почитать
- Martin Fowler: «Feature Toggles» — классическая статья, разбор категорий флагов и антипаттернов.
- LaunchDarkly: Best Practices — вендорский, но с практическими советами.
- Unleash Documentation — open-source альтернатива, концепции rollout/стратегий.