Feature Flags і випуск фіч
Feature Flag (FF) - це керована умова, яка включає/вимикає поведінку системи без релізу коду. Прапори дозволяють: викочувати фічі безпечно, таргетувати групи користувачів/ринків/тенантів, швидко відключати проблемні компоненти, проводити експерименти і конфігурувати параметри в рантаймі.
Ключові цілі:- Знизити blast radius при релізах.
- Розділити розгортання та активацію.
- Дати прозоре управління змінами з аудитом, SLO і відкатом «в один клік».
1) Типи прапорів і коли їх застосовувати
Release flags - поетапне включення нової фічі (dark → canary → ramp-up → 100%).
Ops/kill-switch - миттєве відключення залежностей (провайдер, підсистема, важкі обчислення).
Experiment (A/B, multi-variant) - поділ трафіку на варіанти (weights, sticky bucketing).
Permission/Entitlement - доступ до фічів за ролями/планами/юрисдикціями.
Remote Config - параметри поведінки (поріг, таймаут, формула) з прапора/конфіга.
Migration flags - перемикання схем/шляхів даних (переїзд на новий індекс/БД/ендпоінт).
Анти-патерн: один і той же прапор «про все» - дробіть на фічу, комп-світч і параметри.
2) Модель даних прапора (мінімум)
yaml flag:
key: "catalog. new_ranker"
type: "release" # release ops kill experiment permission config migration description: "New Directory Ranking"
owner: "search-team@company"
created_at: "2025-10-01T10:00:00Z"
ttl: "2026-01-31" # delete deadline after 100% enable rules:
- when:
tenant_id: ["brand_eu","brand_latam"]
region: ["EE","BR"]
user_pct: 10 # progressive percentage then: "on"
- when:
kyc_tier: ["unverified"]
then: "off"
variants: # for experiments
- name: "control"; weight: 50
- name: "v1"; weight: 30
- name: "v2"; weight: 20 payload:
v1:
boost_freshness: 0. 3 boost_jackpot: 0. 2 v2:
boost_freshness: 0. 2 boost_jackpot: 0. 4 prerequisites: # dependent flags/schema versions
- key: "catalog. index_v2_ready"
must_be: "on"
audit:
require_ticket: true change_window: "09:00-19:00 Europe/Kyiv"
safeguards:
max_rollout_pct: 50 # stop threshold auto_rollback_on:
p95_ms: ">200"
error_rate: ">2%"
3) Оцінка і таргетинг (evaluation)
Ключі таргетингу: `tenant_id, region/licence, currency, channel, locale, role, plan, device, user_id, cohort, kyc_tier, experiment_bucket`.
Порядок оцінки: prerequisites → deny-правила → allow-правила → дефолт.
Sticky bucketing: для експериментів хешируйте стабільний ідентифікатор (наприклад,'hash (user_id, flag_key)') - щоб користувач завжди отримував один варіант.
ts result = evaluate(flag, context) // pure function if (!prereqs_ok(result)) return OFF if (deny_match(result, ctx)) return OFF if (allow_match(result, ctx)) return resolve_variant_or_on(result, ctx)
return flag. default
4) Розподіл та архітектура FF
Варіанти:- Server-side SDK (рекомендовано): джерела істинності і кеш в бекенді; уніфікація логіки.
- Edge/CDN evaluation: швидкий таргетинг на периметрі (де немає PII/секретів).
- Client-side SDK: коли потрібна персоналізація UI, але - тільки з мінімальним контекстом і без чутливих правил.
- Config-as-Code: зберігання прапорів в репозиторії, валідація CI, rollout через CD.
- Startup bootstrap + streaming updates (SSE/gRPC) + fallback до останнього снапшоту.
- SLA «freshness» прапорів: p95 ≤ 5 с.
5) Стратегії випуску
5. 1 Dark Launch
Фіча включена, але невидима користувачеві; збираємо метрики і помилки.
5. 2 Canary
Включаємо 1-5% трафіку в одній юрисдикції/тенанті; моніторимо p95/p99, помилки, конверсію.
Stop conditions - порогові тригери автокатофа за метриками.
5. 3 Progressive Rollout
10% → 25% → 50% → 100% за розкладом з ручною/авто-верифікацією.
5. 4 Shadow / Mirroring
Дублюємо запити в новий шлях (без видимого ефекту) і порівнюємо результати/латентність.
5. 5 Blue/Green + FF
Розгортаємо дві версії; прапор рулить трафіком і перемикає залежності по сегментах.
6) Залежності та крос-сервісна консистентність
Використовуйте prerequisites і «health-прапори» готовності: індекс побудований, міграція завершена.
Координація через події: `FlagChanged(flag_key, scope, new_state)`.
1. включити read-шлях → 2) перевірити метрики → 3) включити write/side-effects.
- Сервісні контракти: дефолт повинен бути безпечним (fail-safe OFF).
7) Спостережуваність і SLO
Метрики на прапор/варіант/сегмент:- `flag_eval_p95_ms`, `errors_rate`, `config_freshness_ms`.
- Бізнес-метрики: 'ctr','conversion','ARPU','retention', guardrails (наприклад, RG-інциденти).
- Автоматичні SLO-пороги для автокатофа.
Логи/трейсинг: добавляйте `flag_key`, `variant`, `decision_source` (server/edge/client), `context_hash`.
Дашборди: «сходи» rollout з порогами, heatmap помилок по сегментах.
8) Безпека та комплаєнс
PII-мінімізація в контексті.
RLS/ACL: хто може змінювати які прапори (по доменах/ринках).
Часові вікна змін (change windows) і «подвійне підтвердження» для чутливих прапорів.
Незмінний аудит: хто/коли/що/чому (ticket/incident link).
Юрисдикції: прапори не повинні обходити регуляторні заборони (наприклад, включати гру в забороненій країні).
9) Управління «довгоживучими» прапорами
У кожного прапора є TTL/дата видалення.
Після 100% включення - створіть task на видалення гілок коду, інакше виросте «прапор-борг».
Відзначайте прапори як «migration »/« one-time», відокремлюйте їх від постійних «permission/config».
10) Приклад API/SDK контракту
Evaluation API (server-side)
http
POST /v1/flags/evaluate
Headers: X-Tenant: brand_eu
Body: { "keys":["catalog. new_ranker","rgs. killswitch"], "context": { "user_id":"u42", "region":"EE" } }
→ 200
{
"catalog. new_ranker": { "on": true, "variant":"v1", "as_of":"2025-10-31T12:10:02Z" },
"rgs. killswitch": { "on": false, "variant":null, "as_of":"2025-10-31T12:10:02Z" }
}
Client SDK (кэш, fallback)
ts const ff = await sdk. getSnapshot() // bootstrap const on = ff. isOn("catalog. new_ranker", ctx)
const payload = ff. payload("catalog. new_ranker", "v1")
11) Взаємодія з іншими контурами
Rate limits/квоти: прапори можуть знижувати RPS/включати троттлінг на час інциденту.
Circuit breaker/degradation: kill-switchи відключають важкі шляхи і включають деградацію.
Каталог/персоналізація: прапори змінюють ваги/правила ранжування (через Remote Config).
Міграції БД: прапори поетапно переводять читання/записи на нову схему (read-replica → dual-write → write-primary).
12) Плейбуки (runbooks)
1. Інцидент після включення 25%
Автокатоф спрацював → прапор OFF для всіх/сегмента, тікет в on-call, збір статів, RCA.
Тимчасово включити деградацію/стару гілку через migration-прапор.
2. Зростання p95 за каталогом
Поріг'p95 _ ms> 200'- автокатоф; зафіксувати снапшот логів з'flag _ key = catalog. new_ranker`.
Увімкнути спрощені сигнали ранжування (payload config).
3. Невідповідність юрисдикції
Прапор permission помилково відкрив гру в'NL'- OFF + пост-факт аудит, додавання guard-правила «region deny».
4. Дисперсія в A/B
Зупинити експеримент, виконати CUPED/stratified аналіз, перерозкатати з оновленими вагами.
13) Тестування
Unit: детермінована оцінка правил/пріоритетів/пререквізитів.
Contract: схема прапорів (JSON/YAML), валідатори, CI-перевірка перед мерджем.
Property-based: «deny> allow», «most specific wins», стабільний bucketing.
Replay: відтворення реальних контекстів на новій конфігурації.
E2E: канарні скрипти (step-up/step-down), перевірка автокатофа і аудит-подій.
Chaos: обрив стрімінгу, застарілий снапшот, масове оновлення прапорів.
14) Типові помилки
Секретна логіка в клієнтських прапорах (витоки/підміна).
Відсутність TTL → «кладовище» прапорів в коді.
«Універсальні» прапори без сегментації → неможливо локалізувати проблему.
Немає guardrails/автокатофів - ручні інциденти.
Несумісні залежності між прапорами → цикли/розсинхрон.
Оцінка прапорів в кожному запиті без кеша → сплески латентності.
Відсутність аудиту/вікна змін - ризики комплаєнсу.
15) Чек-лист перед продом
- Прапор створений з типом, owner, описом, TTL і вимогою тікету.
- Правила таргетингу визначені;'deny'на небажані регіони/ролі.
- Sticky bucketing детермінований; ідентифікатор вибраний стабільно.
- Пререквізити і health-прапори готові; Дефолт безпечний.
- Дашборди і алерти на p95/p99, error_rate, бізнес-guardrails.
- Автокатоф налаштований; стоп-поріг rollout і умови відкату.
- Канарковий план: відсотки/етапи/вікно змін/відповідальні.
- Конфіги валідуються в CI; снапшот розподілений по кластерах/регіонах.
- Документація для підтримки/продукту; плейбуки інцидентів.
- План видалення гілок коду і самого прапора після 100%.
16) Приклад «міграційного» прапора (БД/індекс)
yaml flag:
key: "search. use_index_v2"
type: "migration"
description: "Switching reads to index v2"
prerequisites:
- key: "search. index_v2_built"
must_be: "on"
rules:
- when: { tenant_id: ["brand_eu"], user_pct: 5 } then: "on"
- when: { tenant_id: ["brand_eu"], user_pct: 25 } then: "on"
safeguards:
auto_rollback_on:
search_p95_ms: ">180"
error_rate: ">1%"
ttl: "2026-02-01"
Висновок
Feature Flags - це не тільки «вкл/викл», а дисципліна управління ризиками змін. Чіткі типи прапорів, детермінований таргетинг, прогресивні викладки з guardrails, автокатоф, аудит і план видалення роблять релізи передбачуваними, а інциденти - короткими і контрольованими. Вбудовуйте прапори в архітектуру як перший клас громадян - і ви зможете доставляти цінність частіше, безпечніше і осмисленіше.