Czym są feature flagi? Jak je stosować w produkcji

Summary

Feature flagi oddzielają deployment od releasu: kod trafia do produkcji w stanie nieaktywnym, a udostępniasz go stopniowo, ograniczając zasięg awarii. Kluczowe są cztery typy flag (release, eksperyment, ops, uprawnienia), bramki SLO między etapami rollout oraz kill switch projektowany przed incydentem, nie podczas niego. Przy 500+ flagach w systemie, dług flagowy staje się poważnym ryzykiem operacyjnym wpływającym na latencję p99.

Przełączniki feature flag i schemat pipeline wdrożeniowego na ciemnoniebieskim tle

Czym są feature flagi? Jak oddzielić deployment od releasu

Feature flagi to warunkowe wyrażenia w kodzie aplikacji, które kontrolują, które ścieżki kodu uruchamiają się dla danego użytkownika, sesji lub środowiska -- bez konieczności nowego buildu. Flaga new_checkout_flow ustawiona na false dla 99% bazy użytkowników oznacza, że kod został wdrożony dwa tygodnie temu. Po prostu jeszcze jej nie włączono. Kontrakt, który ustanawiają, jest precyzyjny: deployment i release to dwa oddzielne zdarzenia. Dla każdego zespołu robiącego continuous deployment w skali, ten kontrakt jest fundamentem architektury.

Deployment i release to nie to samo zdarzenie

Większość zespołów uczy się tej różnicy po trudnym rollout. Feature wychodzi w środę po południu, coś w śladzie żądania zaczyna zachowywać się inaczej w czwartek rano, a gdy ktoś otwiera śledztwo, diff obejmuje cztery commity i dwie granice serwisów. Przypisanie przyczynowości w takim scenariuszu jest naprawdę trudne.

Feature flagi wymuszają precyzję. Gdy kod za flagą jest scalony i wdrożony, leży nieaktywny w produkcji. Potwierdzasz, że deployment się powiódł, obserwujesz metryki bazowe przez kilka godzin lub dni, sprawdzasz, czy nic się nie pogorszyło. Potem przełączasz flagę dla 1% ruchu. Masz teraz jedną przypisywalną zmienną. Jeśli wskaźnik błędów wzrośnie na ścieżce oznaczonej flagą, nie debugujesz diffa kodu. Przełączasz wartość konfiguracyjną.

To rozdzielenie to przede wszystkim argument o zasięgu awarii (blast radius). Release wpływający na 1% sesji, który idzie źle, można przywrócić w minutach. Release wpływający na 100% sesji, który idzie źle, to poważny incydent.

Mechanizm jest prosty. W TypeScript ewaluacja flagi wygląda mniej więcej tak:

const showNewCheckoutFlow = flagClient.variation(
  'new_checkout_flow',
  { userKey: session.userId, custom: { plan: user.plan } },
  false // domyślna wartość, gdy serwis flagowy jest niedostępny
);

if (showNewCheckoutFlow) {
  return renderNewFlow(cart);
}
return renderLegacyFlow(cart);

Wartość domyślna false to nie formalność. To zachowanie, które dostaną twoi użytkownicy, gdy serwis ewaluacji flag ma awarię sieci. Zdefiniuj ją świadomie, nie przez przypadek.

Cztery typy flag, które naprawdę mają znaczenie w produkcji

Nie wszystkie feature flagi służą temu samemu celowi operacyjnemu. Traktowanie ich jednakowo w bazie kodu i narzędziach zarządzania to pewna droga do zamieszania podczas incydentów i akumulacji długu flagowego.

Flagi release bramkują nowe funkcje podczas developmentu i rollout. Są z założenia tymczasowe: tworzone gdy praca na feature branchu się zaczyna, usuwane gdy funkcja osiąga 100% użytkowników i zespół potwierdził stabilność. Flagi release bez daty usunięcia i bez przypisanego właściciela stają się stałym elementem bazy kodu.

Flagi eksperymentów napędzają testy A/B i eksperymenty wielowariantowe. Są powiązane z identyfikatorami kohort analitycznych, a ich cykl życia jest ograniczony przez eksperyment. Gdy eksperyment się kończy, flaga odchodzi razem z nim. Częsty błąd: zachowanie zwycięskiego wariantu za flagą w nieskończoność, bo usunięcie jest "nieistotne". Dwa lata później flaga eksperymentu jest częścią krytycznej ścieżki i nikt nie pamięta, który wariant jest aktywny.

Flagi ops to kill switche i circuit breakery. W przeciwieństwie do flag release, są zaprojektowane jako stała infrastruktura. Flaga disable_ml_recommendations, która pozwala ominąć wolną warstwę inferencji ML gdy jej SLO się degraduje, jest czymś, co chcesz mieć dostępne o 3 w nocy bez czytania dokumentacji. Te flagi powinny ewaluować lokalnie, mieć dobrze udokumentowany fallback i być regularnie testowane w normalnych operacjach, a nie odkrywane pod presją.

Flagi uprawnień kontrolują dostęp według poziomu użytkownika, planu konta lub kohorty beta. Są długotrwałe z założenia. Ryzyko pomyłki: flagi uprawnień często wyglądają jak flagi release dla czytelnika, który nie zna historii. Jasna konwencja nazewnictwa jest tu ważniejsza niż gdziekolwiek indziej.

Wizualizacja progresywnego wdrożenia oprogramowania pokazująca trasowanie ruchu procentowego z koncentrycznymi kręgami węzłów

Procentowy rollout bez bramki SLO to tylko powolny deployment

Tu większość implementacji feature flag się zatrzymuje. Zespół platformy kabluje harmonogram rollout: 1% w poniedziałek, 5% we wtorek, 25% w środę, 100% w piątek. Dokumentuje to, udostępnia interesariuszom i nazywa progressive delivery.

Ale "progresywny" bez warunku walidacji na każdym etapie to odroczone ryzyko, a nie zredukowane ryzyko. Procentowy przełącznik kontroluje ekspozycję. Nie waliduje bezpieczeństwa.

To, co sprawia, że etapowy rollout ma sens operacyjny, to bramka SLO między każdym etapem. Przed przejściem z 5% do 25%, coś powinno odpowiedzieć: czy wskaźnik błędów na ścieżce oznaczonej flagą mieści się w budżecie SLO? Czy latencja p99 utrzymuje się w tym samym paśmie co grupa kontrolna? Czy budżet błędów spala się szybciej niż bazowa linia?

Jeśli żadne z tych pytań nie jest zainstrumentowane, harmonogram rollout to oś czasu, nie pętla walidacyjna.

Konfiguracja, która się sprawdza w produkcji: zdefiniuj dwa okna ewaluacji SLO. Krótkie okno (15 minut) wychwytuje szybkie awarie -- złe zapytanie do bazy danych, niezgodność schematu, regresję w krytycznej ścieżce. Dłuższe okno (24 godziny lub jeden pełny cykl ruchu) wychwytuje stopniową degradację -- wycieki pamięci, presję cache, przypadki brzegowe w segmentach ruchu o niskiej częstotliwości. Wymagaj, aby oba okna pokazywały zielony kolor przed jakimkolwiek zaawansowaniem. Jeśli którekolwiek okno jest naruszone, zatrzymaj rollout i zadzwoń do on-call.

Procent to pokrętło. Okno SLO to bramka. Oba są wymagane.

Kill switch: zaprojektuj go zanim go potrzebujesz

Kill switch to nie fallback. To decyzja projektowa pierwszej klasy, która powinna istnieć przed napisaniem pierwszej linii kodu funkcji.

Kill switch zaprojektowany pod presją to kill switch z niezbadanymi założeniami. Testujesz go po raz pierwszy podczas aktywnego incydentu, w sesji terminalowej otwartej z powiadomienia PagerDuty, z pięcioma osobami obserwującymi wątek Slack. To najgorszy możliwy moment, aby odkryć, że twoja flaga ops targetuje użytkowników po ID sesji, a serwis sesji jest aktualnie zdegradowany.

Dashboard monitoringu SLO z wykresami wskaźnika spalania budżetu błędów i wskaźnikiem kill switch do kontroli rollout funkcji

Trzy właściwości, które są obowiązkowe dla każdego kill switch przeznaczonego do użytku produkcyjnego:

Zespoły, które sprawnie wykonują reagowanie na incydenty, to te, które ćwiczyły. Kill switch jest częścią runbooka. Uczyń go nudnym.

Dług flagowy: dług techniczny, którego nikt nie wpisuje na roadmapę

Zespoły, które agresywnie adoptują feature flagi, często akumulują dług flagowy: flagi, które wypełniły swój cel, ale nigdy nie zostały usunięte. Funkcja wyszła, eksperyment się zakończył, beta dobiegła końca. Flaga pozostała.

Przy 50 flagach to drobna niedogodność. Przy 500 flagach w rozproszonym systemie to aktywne ryzyko operacyjne. Każda flaga to gałąź kodu, która wymaga utrzymania, testowania i rozumienia podczas badania incydentów. Deweloper próbujący zrozumieć awarię o 2 w nocy nie chce śledzić przez 40 gałęzi warunkowych, aby znaleźć tę właściwą.

Jeden wzorzec zaobserwowany w wielu zespołach platformy: middleware ewaluacji flag pojawiający się w pięciu najwyższych ramkach stosu dla latencji p99. Przyczyną w większości przypadków są przestarzałe flagi ze złożonymi regułami targetowania, ewaluujące dziesiątki warunków na żądanie, niosące ciężar decyzji podjętych dwa lata wcześniej, których nikt nie czuł się komfortowy usuwając.

Środkiem zaradczym jest organizacja, a nie technologia. Każda tworzona flaga powinna mieć trzy atrybuty: właściciela, typ (release, eksperyment, ops, uprawnienia) i oczekiwaną datę usunięcia. Flagi release powinny być usuwane w ciągu dwóch sprintów po pełnym rollout. Flagi eksperymentów powinny być usuwane gdy eksperyment się kończy, a nie "gdy ktoś znajdzie czas". Inwentarz flag powinien być audytowalny na żądanie i widoczny w dashboardach zdrowia inżynieryjnego.

Granularność targetowania: wymiar, który się łamie w skali enterprise

Większość platform feature flag obsługuje rollout procentowy i podstawowe targetowanie atrybutów użytkownika. Luka, która ujawnia się w skali enterprise, to granularność targetowania: zdolność do wyrażania reguł rollout wystarczająco szczegółowych, aby były użyteczne, bez stania się na tyle złożonymi, że stają się nierentowne.

Użyteczna hierarchia targetowania dla rollout produkcyjnych na poziomie zespołu platformy:

  1. Poziom środowiska: produkcja, staging, preview. Pierwsza bramka, nie jedyna.

  2. Segment infrastruktury: centrum danych, strefa dostępności lub klaster Kubernetes. Przydatny do izolowania geograficznego zasięgu awarii.

  3. Konto lub tenant: dla platform SaaS B2B, rollout per-konto jest często bezpieczniejszy niż rollout per-procent-użytkownika, bo możesz obserwować pełny wzorzec ruchu konta zamiast statystycznej próbki.

  4. Kohorta użytkowników: użytkownicy beta, wewnętrzni, power users według poziomu aktywności.

  5. Atrybut sesji: przydatny dla flag eksperymentów, niebezpieczny dla flag ops.

Platformy, które implementują to dobrze (LaunchDarkly i Statsig są najczęściej cytowane przez zespoły SRE robiące to w tej skali) pozwalają na złożone komponowanie reguł bez wymagania czasu inżynierskiego do modyfikacji logiki targetowania podczas aktywnego rollout. Ta zdolność samoobsługi to różnica między 30-sekundową pauzą rollout a ticketem do zespołu platformy.

Platformy, które implementują to słabo, zmuszają do wyboru między granularnością targetowania a prostotą operacyjną. Ten kompromis ujawni się o 3 w nocy.

Co post-mortem wciąż odkrywa

Każdy post-mortem dla incydentu produkcyjnego związanego z funkcją zadaje ten sam zestaw pytań. Czy funkcja była bramkowana za flagą? Czy rollout był progresywny? Czy był warunek walidacji między etapami? Czy kill switch był testowany przed incydentem?

Jeśli wszystkie cztery odpowiedzi są twierdzące, incydent to problem kalibracji: progi ustawione zbyt luźno, reguły targetowania z przypadkiem brzegowym, zachowanie SDK podczas partycji sieci, które nie zostało uwzględnione. To są problemy rozwiązywalne zmianami konfiguracji i aktualizacjami runbooka.

Jeśli jakakolwiek odpowiedź jest przecząca, incydent to problem architektoniczny. Feature flagi to nie wygoda debugowania. To decyzja architektoniczna wdrożenia. Ta decyzja albo istnieje przed wysyłką funkcji, albo w ogóle nie istnieje.

Pytanie warte odpowiedzi przed następnym releasem: co by powiedział post-mortem o tym rollout, gdyby coś poszło nie tak dziś wieczór?

Frequently asked questions

Czym jest feature flag?
Feature flag (flaga funkcji) to warunkowe wyrażenie w kodzie aplikacji, które kontroluje, które ścieżki kodu uruchamiają się dla danego użytkownika, sesji lub środowiska -- bez konieczności nowego buildu czy wdrożenia. Pozwala oddzielić deployment od releasu.
Jakie są główne typy feature flag?
Wyróżniamy cztery kluczowe typy: flagi release (bramkujące nowe funkcje podczas rollout, tymczasowe), flagi eksperymentów (testy A/B, ograniczone czasem eksperymentu), flagi ops (kill switche i circuit breakery, trwała infrastruktura) oraz flagi uprawnień (kontrola dostępu według planu konta, długotrwałe).
Co to jest bramka SLO w kontekście feature flag?
Bramka SLO to warunek walidacji między etapami procentowego rollout. Sprawdza, czy metryki wydajności -- wskaźnik błędów, latencja p99, tempo spalania budżetu błędów -- mieszczą się w zdefiniowanych progach przed zaawansowaniem rollout do kolejnego procentu użytkowników. Bez tej bramki, harmonogram rollout to tylko oś czasu, nie pętla walidacyjna.
Czym jest dług flagowy i jak go ograniczyć?
Dług flagowy to akumulacja flag, które wypełniły swój cel, ale nie zostały usunięte. Przy 500+ flagach w rozproszonym systemie middleware ewaluacji może pojawić się w top-5 ramkach stosu dla latencji p99. Każda flaga powinna mieć właściciela, typ i datę usunięcia. Flagi release usuwa się w ciągu dwóch sprintów po pełnym rollout.
Jak zaprojektować niezawodny kill switch dla produkcji?
Kill switch musi spełniać trzy warunki: lokalna ewaluacja poniżej 50ms (bez wywołań sieciowych), jawna wartość fallback zdefiniowana w kodzie (nie SDK default), i regularne testowanie w scenariuszach awarii zależności -- gdy serwis flagowy jest niedostępny, auth zdegradowane, lub latencja sieci przekracza 2 sekundy.
Dlaczego 78% przedsiębiorstw raportuje większą pewność deploymentu przy progresywnym wdrożeniu?
Progresywne wdrożenie ogranicza zasięg awarii (blast radius): release wpływający na 1% sesji, który idzie źle, jest odwracalny w minutach, podczas gdy release na 100% to poważny incydent. Każdy etap rollout to jedna przypisywalna zmienna, co radykalnie upraszcza debugowanie i ogranicza czas do wykrycia problemu.
Które platformy feature flag są najlepsze dla dużych zespołów SRE?
LaunchDarkly i Statsig są najczęściej cytowane przez zespoły SRE w skali enterprise. LaunchDarkly wyróżnia się w zakresie governance i złożonego targetowania. Statsig łączy flagi z analizą produktową i eksperymentowaniem. ConfigCat to opcja dla tych, którzy cenią prostotę i niższy koszt. Flagsmith to wariant open-source z możliwością self-hostingu.