Feature flag (фича-флаг)
Feature flag (фича-флаг)
Feature flag — это переключатель в коде, который позволяет включать или
выключать отдельную функцию системы без изменения самого кода и без нового
релиза. Код фичи уже задеплоен, но работает только тогда, когда флаг «включён».
История
Сама идея старше термина лет на тридцать. Ещё в 1970-х программисты на C
использовали условную компиляцию — директивы #ifdef, которые включали или
выключали куски кода при сборке программы. Это был «флаг времени компиляции»:
решение принималось один раз, при сборке, и чтобы его поменять, нужно было
пересобрать всё заново.
Современное понимание — «переключатель времени выполнения» (runtime toggle) —
оформилось в эпоху веб-компаний, которым надо было выкатывать код часто и без
простоев. Ключевые вехи:
- Конец 2009 года — инженеры Flickr публикуют знаменитый пост «Flipping
Out» в своём техблоге. Они рассказывают, как деплоят код десятки раз в день,
а незаконченные фичи прячут за флагами. Это первый громкий публичный рассказ
о практике. - 2010 год — Мартин Фаулер (Martin Fowler), один из самых цитируемых
авторов в индустрии, описывает паттерн «Feature Toggle» в своём блоге-вики.
Термин закрепляется. - Начало 2010-х — Facebook строит внутреннюю систему Gatekeeper, через
которую любая фича включается на долю процента пользователей, потом на 1%,
10% и так далее. Etsy строит похожую культуру и деплоит до 50 раз в день. - 2014 год — Эдит Харбо (Edith Harbaugh) и Джон Кодумал (John Kodumal)
основывают LaunchDarkly — первый крупный коммерческий сервис «флаги как
услуга». Примерно тогда же в норвежской компании Finn.no рождается
open-source система Unleash. - 2017 год — Пит Ходжсон (Pete Hodgson) публикует на сайте Фаулера
большую статью «Feature Toggles (aka Feature Flags)», которая до сих пор
считается каноническим текстом: там введена классификация флагов на четыре
типа (release, experiment, ops, permission).
Сегодня это стандартная практика: флаги встроены в Firebase (Remote Config от
Google), есть у GitLab, GitHub, Amazon, а рынок специализированных сервисов —
LaunchDarkly, Split, Flagsmith, GrowthBook, Unleash — оценивается в миллиарды
долларов.
Что это такое
Представь, что у тебя в системе есть новая функция — например, новый способ
проверки входящих заявок. Классический путь: написал код → протестировал →
задеплоил → функция работает у всех сразу. Если что-то пошло не так — откат,
то есть новый деплой старой версии, паника, простой.
Feature flag разрывает жёсткую связку «код задеплоен = код работает». Код
новой функции попадает на сервер, но оборачивается в условие:
если флаг "новая_проверка" включён:
выполнить новую проверку
иначе:
выполнить старую проверку
Само значение флага («включён/выключен») хранится не в коде, а снаружи: в
конфиге, в базе данных, в специальном сервисе. Поменять его можно за секунды —
галочкой в админке, без пересборки и передеплоя.
Из этого простого приёма вырастает несколько разных инструментов. По
классификации Ходжсона:
- Release toggle (релизный флаг) — прячет незаконченную фичу. Код уже в
основной ветке, но выключен. Живёт дни или недели, потом удаляется. - Experiment toggle (экспериментальный флаг) — половине пользователей
показываем вариант A, половине вариант B, сравниваем метрики. Это основа
A/B-тестирования. - Ops toggle (операционный флаг) — рубильник для эксплуатации. Если
внешний сервис лёг или нагрузка зашкаливает, дежурный выключает тяжёлую
функцию, и система продолжает работать в упрощённом режиме. Частный случай —
kill switch (аварийный выключатель). - Permission toggle (флаг доступа) — фича включена только для избранных:
бета-тестеров, платных клиентов, сотрудников компании.
Важная пара для различения: feature flag vs ветка в git. Ветка изолирует
код до попадания в основную версию; флаг изолирует поведение уже
задеплоенного кода. Флаги позволяют сливать код в основную ветку рано и часто
(это называется trunk-based development), не боясь, что незаконченное сломает
прод. И вторая пара: feature flag vs конфиг. Обычный конфиг читается при
старте программы и один для всех; флаг может вычисляться на каждый запрос и
давать разным пользователям разный ответ.
Аналогии из жизни
Электрощиток в квартире. В щитке стоят автоматы: можно обесточить одну
кухню, не выключая весь дом. Ops toggle работает так же: сломалась одна
«комната» системы — отключил её, остальное живёт.
Где ломается: автомат в щитке либо включён, либо выключен для всех розеток
сразу. А фича-флаг умеет тоньше: «выключено для всех, кроме 5% пользователей
из Москвы». У электрика такой магии нет.
Новое блюдо в ресторане. Шеф уже отработал рецепт, продукты закуплены,
повара обучены — но в печатное меню блюдо не попало. Официанты предлагают его
только «своим» — постоянным гостям, чтобы собрать отзывы. Это permission
toggle: функция физически готова, но доступна избранным.
Где ломается: официант может забыть, кому предлагать, а кому нет — человек
ошибается. Флаг детерминирован: одно и то же правило применяется миллион раз
одинаково. Зато у официанта есть здравый смысл, а флаг с ошибкой в правиле
будет миллион раз одинаково ошибаться.
Репетиция оркестра за закрытым занавесом. Оркестр играет новую программу в
настоящем зале, с настоящей акустикой — но публику ещё не пустили. В IT это
называется dark launch (тёмный запуск): новый код уже обрабатывает реальные
запросы, но его результаты никому не показываются, только записываются для
сравнения со старым кодом.
Где ломается: репетиция не нагружает гардероб и кассы, а тёмный запуск
нагружает систему по-настоящему — новый код ест процессор и память прямо на
проде. Если он прожорлив, «репетиция» уронит и «спектакль».
Как это работает
Разберём путь одного флага — от галочки в админке до поведения системы.
Шаг 1. Объявление. Разработчик заводит флаг с именем, например
skip_blacklist_check, и значением по умолчанию false. Где заводит — зависит
от масштаба: в маленькой системе это поле в конфиг-файле или переменная
окружения, в большой — запись в специальном сервисе флагов.
Шаг 2. Ветвление в коде. Во всех местах, где поведение должно зависеть от
флага, появляется проверка:
flags = load_flags() # прочитать состояние флагов
if flags["skip_blacklist_check"]:
log("проверка ЧС пропущена по флагу")
result = "skipped"
else:
result = check_blacklist(phone)
Обрати внимание на строчку с логом: хороший тон — всегда писать в лог, что
сработал именно флаг. Иначе через месяц никто не поймёт, почему система ведёт
себя «странно».
Шаг 3. Доставка значения. Тут три схемы по нарастанию сложности:
- Статическая: флаг в конфиге, читается при старте. Чтобы поменять — правишь
конфиг и перезапускаешь процесс. Просто, но медленно. - Динамическая с опросом: приложение раз в N секунд спрашивает у сервиса
флагов «что поменялось?» (это называется polling — периодический опрос).
Изменение долетает за секунды без рестарта. - Динамическая с push: сервис флагов сам рассылает изменения подписчикам
через постоянное соединение. Долетает почти мгновенно.
Шаг 4. Таргетинг (прицеливание). В зрелых системах флаг — не просто
да/нет, а правило: «включено для 10% пользователей», «включено для всех, у
кого email на @company.com», «включено в Германии». Чтобы один и тот же
пользователь стабильно попадал в одну и ту же группу, его идентификатор
прогоняют через хеш-функцию (детерминированное превращение строки в число) и
смотрят, в какой процентный «карман» попало число.
Шаг 5. Раскатка и уборка. Типичный жизненный цикл релизного флага:
включили на сотрудниках → на 1% пользователей → посмотрели на ошибки и
метрики → 10% → 50% → 100% → выждали неделю-две → удалили флаг и старую
ветку кода. Последний шаг — самый важный и самый часто пропускаемый.
Каждый живой флаг удваивает число состояний системы: 10 флагов — это
2^10 = 1024 возможные комбинации поведения, которые никто никогда не
протестирует целиком.
Забытый флаг — это заряженное ружьё
1 августа 2012 года трейдинговая компания Knight Capital потеряла около 460 миллионов долларов за 45 минут. По материалам расследования SEC, при деплое нового кода на один из восьми серверов обновление не попало, а флаг, который переиспользовали для новой функции, активировал на этом сервере мёртвый код восьмилетней давности — тот начал заваливать биржу ордерами. Компания не пережила этот день как самостоятельный бизнес. Мораль: флаги нужно удалять, а не переиспользовать.
Где встречается в обычной жизни
- «У тебя в приложении уже есть эта кнопка, а у меня нет» — хотя версия
приложения одинаковая. Это постепенная раскатка: ты просто ещё не попал в
процент включённых. - Банковское приложение в чёрную пятницу вдруг прячет второстепенные
разделы или показывает упрощённый экран — это ops toggle: под пиковой
нагрузкой отключили всё тяжёлое, чтобы платежи продолжали ходить. - Интерфейс изменился без обновления из магазина приложений — новый вид
главного экрана «приехал» через remote config, разновидность флагов. - Бета-программы: «включить экспериментальные функции» в настройках — это
ты сам себе переключаешь permission toggle. - Игры и промо-акции, стартующие у всех одновременно, секунда в секунду:
код события залили заранее, а в час X просто щёлкнули флагом.
Где встречается в IT и бизнесе
- Непрерывная поставка (continuous delivery). Нужно, когда команда хочет
деплоить часто и маленькими порциями: код сливается в основную ветку
ежедневно, незаконченное прячется за флагами, релиз перестаёт быть событием. - A/B-тестирование и продуктовые эксперименты. Нужно, когда решения о
фичах принимают по метрикам: флаг делит аудиторию, аналитика сравнивает
конверсию. - Аварийные рубильники вокруг внешних зависимостей. Нужно, когда твоя
система зависит от чужих API: платёжный провайдер лёг — флагом переключились
на резервного или на ручной режим, не будя разработчиков среди ночи. - Продажи и тарифные планы. Нужно, когда функциональность продаётся
пакетами: «продвинутая аналитика» включается флагом для тех, кто заплатил.
Это уже граница с системой прав доступа. - Миграции без остановки. Нужно, когда меняешь базу данных или ключевой
алгоритм: старый и новый путь работают параллельно, флаг постепенно
переводит трафик, в любой момент можно вернуться назад.
Кто пользуется
- Facebook/Meta — внутренняя система Gatekeeper управляет раскаткой фич на
миллиарды пользователей; практически ни одна фича не включается сразу на всех. - Google — раскатка функций в Chrome и Android идёт через флаги и
экспериментные группы; в Chrome даже есть страницаchrome://flags, где
пользователь сам может пощёлкать экспериментальные функции. - Netflix — флаги плюс автоматический анализ метрик: если после включения
фичи проседает качество стриминга, система сама откатывает. - LaunchDarkly — по собственным заявлениям, обслуживает триллионы
вычислений флагов в сутки для тысяч компаний-клиентов. - GitLab — разрабатывает свой продукт в открытом репозитории и прячет
незаконченное за флагами; их документация по феномену флагов — одна из самых
подробных публичных.
Альтернативы и конкуренты
- Долгоживущие feature-ветки в git.
Плюс: код фичи полностью изолирован, в основной ветке его физически нет.
Минус: чем дольше живёт ветка, тем страшнее слияние («merge hell»);
интеграционные проблемы всплывают в самом конце, когда исправлять дороже всего. - Blue-green деплой (два одинаковых окружения, переключение трафика).
Плюс: мгновенный откат всего релиза целиком, честная проверка на боевой
инфраструктуре.
Минус: двойная инфраструктура стоит двойных денег; гранулярность — «весь
релиз», отдельную фичу не выключишь. - Канареечный деплой на уровне балансировщика.
Плюс: не требует менять код приложения вообще.
Минус: делит трафик по серверам, а не по пользователям и не по фичам; тонкий
таргетинг («только беты», «только Германия») недоступен. - Конфиги и переменные окружения с рестартом.
Плюс: нулевая дополнительная сложность, есть в любой системе.
Минус: нужен рестарт процесса; значение одно для всех; нет постепенной
раскатки и аудита «кто и когда переключил».
Когда НЕ стоит использовать
- Маленький проект без пользователей (скрипт, пет-проект, внутренняя
утилита на трёх человек) — потому что накладные расходы (ветвления в коде,
учёт флагов, уборка) превышают пользу; откатиться через git быстрее. - Как постоянная система прав доступа — потому что для «этому можно, тому
нельзя» существуют нормальные механизмы авторизации (роли, permissions) с
аудитом и управлением. Флаг, живущий годами, — это не флаг, а плохо
документированная настройка. - Для обхода проверок безопасности «на минуточку» — потому что флаг
«временно без аутентификации» имеет свойство оставаться включённым навсегда,
а найдёт его первым не автор, а злоумышленник или аудитор.
Флаг — это кредит, а не подарок
Каждый флаг берёт в долг у будущей простоты системы. Пока флаг живёт, все, кто читает код, должны держать в голове оба варианта поведения. Команды, у которых флаги работают хорошо, отличаются не тем, как они флаги заводят, а тем, как дисциплинированно они их удаляют: срок жизни в описании флага, регулярная ревизия, тикет на удаление создаётся вместе с тикетом на создание.
Связанные понятия
- Trunk-based development — практика, при которой все разработчики сливают
код в одну основную ветку как минимум ежедневно; флаги делают её возможной. - Canary release (канареечный релиз) — выкатка новой версии на малую долю
серверов или пользователей с наблюдением за метриками перед полной раскаткой. - Blue-green deployment — два параллельных боевых окружения, трафик
переключается между ними целиком. - A/B-тестирование — сравнение двух вариантов продукта на живых
пользователях по метрикам; экспериментальные флаги — его механика. - Kill switch — аварийный выключатель функции или всей системы; частный
случай операционного флага. - Technical debt (технический долг) — накопленная цена быстрых решений;
неудалённые флаги — одна из его типичных форм.
Литература и источники
- Pete Hodgson, «Feature Toggles (aka Feature Flags)» —
https://martinfowler.com/articles/feature-toggles.html — канонический текст
с классификацией флагов (en). - Jez Humble, David Farley, «Continuous Delivery» (2010, en; есть русский
перевод «Непрерывное развёртывание ПО») — контекст, в котором флаги стали
необходимостью. - Nicole Forsgren, Jez Humble, Gene Kim, «Accelerate» (2018, en; русский
перевод «Ускоряйся!») — исследование о связи частых релизов и эффективности
компаний. - Пост Flickr «Flipping Out» (2009) — искать в Google по запросу
«Flickr Flipping Out feature flags code blog». - Разбор инцидента Knight Capital — искать «SEC Knight Capital 2013 order» и
«Knight Capital Power Peg postmortem». - Wikipedia: https://en.wikipedia.org/wiki/Feature_toggle (en) — обзор и
терминология.
Где встретилось у меня
Вчера чинил бизнес-агента, который передаёт заявки в колл-центр: этап проверки
номеров по чёрному списку сломался из-за изменений на стороне внешнего
SSO-сервиса, и вместо ожидания чужого фикса мы провели через все слои системы
— от веб-интерфейса до консольного конвейера — флаг «Пропустить ЧС». Классический
ops toggle: система продолжает работать в упрощённом режиме, а флаг выключим,
когда внешний сервис починят.
Краткое резюме
- Feature flag — переключатель, разрывающий связку «задеплоено = работает»:
код на сервере, но включается отдельным решением, без релиза. - Четыре типа: релизные (спрятать незаконченное), экспериментальные (A/B),
операционные (аварийный рубильник), флаги доступа (для избранных). - Главная сила — скорость и обратимость: включить фичу на 1% пользователей и
выключить за секунды при проблемах. - Главная опасность — забытые флаги: каждый живой флаг удваивает число
состояний системы, а переиспользованный флаг стоил Knight Capital ~460 млн
долларов за 45 минут. - Правило зрелой команды: флаг создаётся сразу с планом удаления.