Инженерная практика
Feature-флаги отвязывают деплой от релиза
«Я не могу мёржить ежедневно — моя фича не закончена. Я не могу положить половину flow checkout-а на trunk.» Это возражение топит большинство внедрений trunk-based, и оно держится на скрытом допущении: что положить код в прод значит показать его пользователям. Разделите эти два — и возражение растворяется. Полузаконченный flow checkout-а уезжает в прод сегодня, прогоняется через CI, лежит там полностью интегрированный — и ни один пользователь не может до него добраться, потому что он за выключенным флагом. Вы развернули код. Вы не выпустили фичу.
Деплой и релиз — разные события
Связывание «деплоя» и «релиза» в один акт — вот что вынуждает к долгоживущим веткам: если выкатить код — то же, что показать фичу, то незавершённая работа должна оставаться вне trunk, пока не готова. Feature-флаги разбивают эту связку. Развёртывание — это перенос кода на прод-серверы. Релиз — это сделать фичу достижимой пользователями. Флаг — рантайм-переключатель между ними: оберните новый путь в условие, читающее флаг, выкатите его выключенным — и код развёрнут, интегрирован и протестирован, но тёмный: присутствует и недостижим.
Именно это делает ежедневную интеграцию совместимой с многонедельными фичами. Работа мёржится в trunk каждый день как малые зелёные коммиты, каждый спрятан за выключенным флагом, так что вы никогда не накапливаете разрыв (урок 1) и никогда не нуждаетесь в долгоживущей ветке (урок 2). Когда фича завершена, вы ничего не развёртываете — вы переключаете флаг. Релиз перестаёт быть рискованным большим пушем и становится изменением конфигурации, которое можно сделать в 10 утра во вторник, пока автор смотрит на дашборды.
Dark launch и постепенная экспозиция
Когда релиз стал рантайм-решением, вы получаете возможности, которых деплой дать не может. Dark launching означает прогонять новый путь кода в проде до показа его результатов пользователям — например, слать реальный трафик на новый сервис рекомендаций, сравнивать его вывод со старым и измерять задержку, но выбрасывать новый вывод. Вы нагрузочно тестируете и валидируете против реальности прода с нулевым видимым для пользователя риском. Затем вы постепенно экспонируете: включаете фичу для внутренних пользователей, потом 1%, потом 5%, 25%, 100%, наблюдая за частотой ошибок и задержкой на каждом шаге. Это canary через флаг — blast radius растёт только по мере роста уверенности.
Тот же переключатель — ваш самый быстрый инструмент восстановления. Если разогнанная фича ведёт себя плохо на 5%, вы выключаете флаг — kill switch — и каждый пользователь возвращается на старый путь за секунды, без отката-деплоя, без revert-PR, без ожидания CI. Отвязывание деплоя от релиза превращает «мы выкатили баг, начинаем инцидент» в «мы его выключили, теперь спокойно дебажим».
| Тип флага | Назначение | Ожидаемое время жизни | Кто его переключает |
|---|---|---|---|
| Release | Спрятать незавершённую работу; разогнать выкатку | Дни–недели — удалить после 100% | Разработчик / владелец релиза |
| Ops / kill switch | Отключить фичу под нагрузкой/в инциденте | Долгоживущий по дизайну | On-call / ops |
| Experiment | A/B-тест, проверить гипотезу | Один цикл эксперимента | Продукт / данные |
| Permission / entitlement | Гейтить фичи по плану/роли | Постоянный (это продуктовое правило) | Продукт / рантайм |
Не каждый флаг — один и тот же зверь
Одно слово «флаг» прячет четыре очень разные вещи, и их смешение — это как гниют системы флагов. Release-флаг — временные леса: он существует, чтобы прятать незавершённую работу и разгонять выкатку, и должен быть удалён, как только фича на 100%. Ops-флаг (kill switch) призван жить вечно, чтобы вы могли сбрасывать нагрузку или отключать сбоящую подсистему во время инцидента. Experiment-флаг живёт один A/B-цикл. Permission-флаг постоянен, потому что кодирует продуктовое правило (эта фича — для планов Pro). Опасная категория — release-флаг, потому что он выглядит постоянным, если о нём забыть — а забытый release-флаг — это проблема flag debt из следующего урока.
Почему это работает
Причина, по которой «отвяжи деплой от релиза» — это ключ к trunk-based, не в самих флагах — а в том, что это убирает единственную честную причину держать работу вне trunk. Без флагов «моя фича не готова» — реальный аргумент за долгоживущую ветку. С флагами незавершённая работа имеет безопасный дом в проде, так что больше нет оправдания давать ветке накапливать разрыв. Флаг — это то, что делает «интегрируйся ежедневно» достижимым для работы, занимающей месяц.
Вы выкатываете переписанное ранжирование поиска, затрагивающее каждый запрос. Как выпустить его с наименьшим blast radius?
Какое скрытое допущение делает «я не могу мёржить ежедневно, моя фича не готова» ощущаемым как истина — и как флаг его растворяет?
Какой тип флага — это временные леса, которые должны быть удалены после того, как фича достигла 100%?
Упорядочьте безопасный релиз рискованной фичи с помощью флагов:
- 1 Мёржить работу в trunk ежедневно за выключенным release-флагом — развёрнуто, но тёмно
- 2 Dark launch: прогнать новый путь в проде, сравнить вывод, выбросить его
- 3 Включить для внутренних пользователей, затем разогнать 1% → 25% → 100%, наблюдая за метриками
- 4 Держать наготове kill switch для выключения за секунды, если метрики регрессируют
- 5 На стабильных 100% удалить release-флаг и мёртвый старый путь
- 01Объясните, почему отвязывание деплоя от релиза — это та конкретная вещь, что заставляет trunk-based работать для многонедельных фич.
- 02Помимо прятания незавершённой работы, какие операционные возможности даёт флаг, и почему таксономия флагов важна?
Ежедневная интеграция многонедельной работы возможна только потому, что развёртывание кода и выпуск фичи — разделимые события, а feature-флаг — рантайм-переключатель между ними: оберните новый путь в выключенное условие, и код уезжает в прод тёмным — интегрированным и протестированным, но недостижимым. Это даёт незавершённой работе безопасный дом на trunk, так что вам никогда не нужна долгоживущая ветка, и превращает релиз из рискованного деплоя в изменение конфигурации. Это также открывает операционную мощь: dark launching валидирует новый код против реального трафика без влияния на пользователей, постепенная экспозиция разгоняет blast radius с уверенностью, а kill switch делает восстановление переключением за секунды вместо отката. Но «флаг» смешивает четырёх зверей с разным временем жизни — временные release-флаги, постоянные ops kill switch-и, одноцикловые experiment-флаги и постоянные permission-флаги — и release-флаг — тот, что должен быть удалён на 100%, иначе он тихо становится flag debt из следующего урока.