Feature flags: как отделить деплой кода от включения функции

Feature flags: как отделить деплой кода от включения функции

Новая функция может уже находиться в production-коде и при этом оставаться недоступной пользователям. Для этого поведение приложения помещают за feature flag — условием, которое вычисляется во время выполнения и определяет, какую ветку логики использовать.

Так появляется важное разделение. Deploy отвечает на вопрос, какой код развёрнут. Release — какое поведение стало доступно. Experiment — сравниваются ли разные варианты по заранее определённой процедуре. Feature flag может связывать эти процессы, но не делает их одним и тем же событием.

Feature flag — это условие выбора поведения во время выполнения

В простейшем случае логика выглядит почти тривиально:

if feature_enabled("new_checkout"):
    use_new_checkout()
else:
    use_old_checkout()

Смысл появляется не в самом if, а в том, что значение условия можно определять отдельно от нового deploy.

OpenFeature описывает feature flag как механизм runtime evaluation. Приложение запрашивает значение флага, а система feature management возвращает вариант с учётом правил и контекста. Microsoft Azure App Configuration также позволяет динамически включать и выключать возможности приложения без обязательного перезапуска или повторного развёртывания.

Из-за этого один и тот же build может поддерживать несколько допустимых состояний поведения.

Схема работы feature flag и evaluation context

Deploy и release лучше считать разными событиями

Без feature flag новая логика часто становится активной сразу после установки новой версии. Тогда два события практически совпадают:

новый код развёрнут → новое поведение включено.

С флагом последовательность может быть другой:

новый код развёрнут → флаг выключен → система продолжает старое поведение → флаг включён → новое поведение становится доступным.

Такое разделение удобно по нескольким причинам:

  • код можно доставить заранее;
  • момент включения становится отдельным событием;
  • функцию можно открыть только определённой аудитории;
  • при предусмотренной архитектуре можно быстро вернуть прежнее поведение переключением флага;
  • одно и то же изменение проще привязать к журналу наблюдений.

При этом feature flag не отменяет требований к качеству deploy. Если новый код ломает загрузку приложения ещё до проверки флага, выключенное состояние не спасёт систему.

Release и experiment тоже не одно и то же

Включить функцию для части пользователей можно по разным причинам.

Например, команда хочет:

  • дать доступ внутренней группе;
  • открыть функцию конкретным клиентам;
  • включить новую возможность постепенно;
  • сравнить две вариации поведения;
  • оставить аварийный переключатель для операционной команды.

Только часть этих сценариев является экспериментом.

LaunchDarkly отдельно выделяет experiment flags как временные флаги, которые используются вместе с метриками для сравнения вариантов. Само наличие двух вариаций ещё не превращает переключение в эксперимент. Для этого нужен вопрос, процедура сравнения и измеряемый результат.

Поэтому полезно различать три уровня:

Событие Что происходит
Deploy Новая версия кода появляется в среде
Release Новое поведение становится доступным выбранной аудитории
Experiment Варианты поведения сравниваются по определённой методике

У флага должно быть понятное выключенное состояние

Фраза «если флаг выключен, функция не работает» не всегда достаточно точна.

Нужно заранее решить, что именно получает система в состоянии off:

  • старую реализацию;
  • отсутствие нового элемента интерфейса;
  • запрет выполнения операции;
  • безопасное значение по умолчанию;
  • другой вариант поведения.

Это особенно важно при ошибке получения конфигурации флага. OpenFeature Evaluation API предполагает наличие default value, которое передаётся при вычислении флага. Конкретное приложение всё равно должно решить, какое значение действительно безопасно для его сценария.

Поэтому fallback — часть инженерного дизайна, а не техническая мелочь SDK.

Evaluation context определяет, для кого включится функция

Feature flag не обязательно возвращает одно значение для всех запросов. Решение может зависеть от контекста.

OpenFeature называет этот набор данных evaluation context. В него могут входить сведения о среде выполнения, приложении, хосте или субъекте, для которого вычисляется флаг. Эти данные используются как основа для targeting и других правил.

Практически это позволяет строить условия вроде:

  • включить новую функцию только во внутреннем окружении;
  • дать доступ определённой группе;
  • использовать вариант только для части запросов;
  • включить новое поведение для выбранного сегмента.

Но контекст не стоит превращать в случайный набор всех доступных данных. Для правила должны использоваться только те атрибуты, которые действительно нужны для вычисления.

И отдельно нужно учитывать требования к приватности. Если система flagging получает пользовательские атрибуты, команда должна понимать, какие данные передаются и зачем.

Состояние feature flag становится частью состояния системы

После появления флагов одной версии кода уже недостаточно, чтобы описать фактическое поведение приложения.

Два экземпляра одного build могут работать по-разному:

Параметр Состояние A Состояние B
Build 2.8.0 2.8.0
Флаг new_checkout off on
Поведение Старая реализация Новая реализация

Поэтому для инженерной проверки важно фиксировать не только commit или release, но и:

  • имя или идентификатор флага;
  • его вариант;
  • время изменения;
  • среду;
  • правила targeting, если они влияют на проверку;
  • аудиторию, которая получила новое состояние.

Эту информацию логично связывать с журналом эксперимента. Тогда момент переключения не теряется между Git history, релизом и системой feature management.

Feature flag помогает изолировать момент включения, но не все зависимости

Флаг хорошо отделяет доставку кода от активации поведения. Но он не превращает сложное изменение в одну независимую переменную.

Например, новая функция может требовать:

  • новой схемы базы данных;
  • другого формата сообщения;
  • новой версии клиентского приложения;
  • подготовленных фоновых данных;
  • изменения внешнего API.

Если старый и новый пути не могут существовать одновременно, простой boolean flag не решит задачу совместимости.

Поэтому перед внедрением нужно проверить, что состояние off действительно остаётся работоспособным после deploy нового кода. Иначе флаг создаёт иллюзию обратимости, которой на самом деле нет.

Флаги увеличивают число состояний, которые нужно тестировать

Одна функция с состояниями on и off добавляет два варианта поведения. Несколько зависимых флагов способны увеличить число комбинаций намного сильнее.

Из этого не следует, что нужно тестировать абсолютно все математически возможные сочетания. Но основные состояния должны быть определены заранее.

Минимально стоит проверить:

  • основной путь при выключенном флаге;
  • основной путь при включённом флаге;
  • переход между состояниями, если он происходит во время работы;
  • поведение при недоступности конфигурации;
  • существенные взаимодействия с другими флагами.

LaunchDarkly в руководстве по тестированию кода с feature flags отдельно рассматривает сложность, возникающую из-за нескольких вариантов и комбинаций флагов. Поэтому управление флагами должно включать не только переключение, но и тестовую стратегию.

Feature flag и canary deployment контролируют разные уровни

Эти подходы часто используют вместе, но их полезно не смешивать.

Feature flag обычно определяет, какое поведение выполняет уже развёрнутый код.

Canary deployment управляет тем, какая версия приложения или инфраструктуры получает часть реального трафика.

Условная схема выглядит так:

Feature flag:
один build → старая функция / новая функция

Canary:
stable build / canary build → разные части трафика

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

Но это уже два слоя управления, и их события нужно фиксировать отдельно. Подробнее разницу и устройство постепенного развёртывания разберём в материале о canary deployment.

Временный флаг должен иметь конец жизненного цикла

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

Для временных флагов это технический долг.

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

Полезно ещё при создании определить:

Поле Что указать
Назначение Зачем существует флаг
Владелец Кто отвечает за его состояние
Тип Временный или постоянный
Состояние после завершения Какая ветка должна остаться в коде
Условие удаления Когда флаг больше не нужен

Так cleanup становится частью жизненного цикла, а не отдельным проектом спустя год.

Жизненный цикл feature flag: создание флага, переключение поведения, удаление из кода и архивация

Постоянный флаг тоже требует понятного назначения

Не каждый feature flag нужно удалять. Некоторые переключатели действительно являются постоянным механизмом управления системой.

Например, это может быть операционный выключатель функции или долгоживущая конфигурация поведения.

Но постоянный статус не означает, что такой флаг можно оставить без владельца и документации. Для него всё равно нужны:

  • понятное имя;
  • описание назначения;
  • определённое безопасное состояние;
  • правила изменения;
  • контроль зависимостей от других флагов.

Иначе feature management постепенно превращается во второй, плохо документированный слой конфигурации.

Когда feature flag особенно полезен

Механизм хорошо подходит, когда новое и старое поведение могут некоторое время существовать рядом и команде важно управлять моментом переключения.

Типичные сценарии:

  • развёрнуть код заранее, но включить функцию позже;
  • дать доступ внутренней группе перед общим release;
  • переключить поведение для выбранного сегмента;
  • провести контролируемое сравнение вариантов;
  • оставить быстрый операционный выключатель там, где архитектура допускает безопасное возвращение.

Feature flag хуже подходит как попытка скрыть архитектурно несовместимые изменения или заменить полноценный rollback там, где новое состояние уже необратимо изменило данные.

Минимальная схема работы с feature flag

  1. Определить цель. Зачем флаг нужен и какое поведение он разделяет.
  2. Описать состояния. Что происходит при каждом варианте.
  3. Выбрать безопасный default. Что должно произойти при невозможности получить нормальное решение.
  4. Определить targeting. Для кого и при каких условиях включается вариант.
  5. Протестировать обе ветки. Включая важные переходные сценарии.
  6. Зафиксировать момент переключения. Связать его с журналом изменений или эксперимента.
  7. Не смешивать release с экспериментом. Само распределение вариантов ещё не является доказательной процедурой.
  8. Запланировать cleanup. Если флаг временный, заранее определить, когда удалить ненужную ветку.

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

Источники

Технические источники проверены 19 августа 2026 года. Использованы официальные спецификации и документация OpenFeature, Microsoft и LaunchDarkly.