Co to jest feature flag: Przewodnik dla Engineering Teamów
Summary
Feature flag to warunki w kodzie decydujące w runtime czy funkcjonalność jest włączona. Zespoły używają ich do merging niedokończonej pracy, stopniowych rolloutów i szybkich kill switchy. Jednak 75% flag żyje zbyt długo - przewodnik wyjaśnia typ, właściciela i cleanup proces.
Feature flag to warunki w kodzie, które decydują w runtime, czy dana funkcjonalność jest włączona lub wyłączona bez nowego deployu. To cała idea.
Co to jest feature flag w praktyce? Instrukcja if, która bierze odpowiedź z konfiguracji, wiersza w bazie danych lub serwisu flag zamiast być na stałe wkodowana.
Koncepcja jest prosta. Żyć ze 200 takimi flagami w repozytorium to nie jest, a właśnie ta druga część to jest temat tego przewodnika.
Jak wygląda feature flag w kodzie?
Oto najmniejsza użyteczna wersja:
if (flags.isEnabled("new-checkout", { userId })) {
return renderNewCheckout();
}
return renderOldCheckout();Oba warianty kodu wysyłacie razem w tym samym buildie. Wartość flaga żyje gdzieś, gdzie możecie ją zmienić bez redeploy: w zmiennej środowiskowej, pliku JSON, tabeli lub hostowanym serwisie. Zmieńcie wartość, a zachowanie zmienia się przy następnej ewaluacji.
To rozdzielenie to właśnie punkt. Deployment to umieszczanie kodu na serwerach. Release to pozwolenie użytkownikom go widzieć. Flagi dzielą te dwa momenty, więc merge do main już nie oznacza "wszyscy to dostaną teraz".

Dlaczego zespoły w ogóle używają feature flagów?
Trzy powody pojawiają się w kółko w zespołach 5-50 inżynierów.
Bezpiecznie mergujcie niedokończoną pracę. Commitujecie niedokończoną funkcjonalność za flagą, która jest wyłączona, a Wasza gałąź nigdy nie żyje przez trzy tygodnie. To jest to, co sprawia trunk-based development wykonalnym.
Stopniowo puszczajcie zmiany. Włączcie zmianę dla użytkowników wewnętrznych, potem dla 5% ruchu, potem dla wszystkich. Jeśli wskaźniki błędów rosną, przerzucacie to wstecz w sekundy.
Szybko wyłączcie coś. Kiedy dostawca płatności wysypuje się o 2 w nocy, flaga pozwala on-call zdegradować jedną funkcjonalność zamiast rollbackować całą release.
Żaden z tych przypadków nie wymaga vendora. Flaga może być booleanem w tabeli konfiguracyjnej. Pomijajcie platformę, dopóki nie będziecie potrzebować rolloutów procentowych, audit trail lub nieinżynierów przełączających rzeczy.
Jakie są cztery typy feature flagów?
Szeroko cytowany artykuł Pete'a Hodgsona Feature Toggles na stronie Martina Fowlera soruje flagi według tego, jak długo żyją i jak często decyzja się zmienia. Kategorie są wciąż najbardziej przejrzystym modelem mentalnym.
Release: żyje dni do tygodni, przerzucana przez inżynierów. Przykład: ukrycie niedokończonego redesignu kasy.
Experiment: żyje tygodni, przerzucana przez product i data team. Przykład: A/B test dwóch stron cennika.
Ops: żyje godziny do zawsze, przerzucana przez on-call. Przykład: kill switch dla wolnego serwisu rekomendacji.
Permission: żyje miesiące do lat, przerzucana przez product i support. Przykład: dostęp beta lub funkcjonalności tylko premium.
Kolumna lifespan jest najważniejsza. Flaga release, która przetrwa swoją release to bug, który nie znaleźliście. Flaga permission, która zostanie usunięta w sprint czyszczenia to outage, która nie miała jeszcze miejsca.
Nazwijcie i zaetykietujcie typ kiedy tworzysz flagę. Sześć miesięcy później, nikt nie pamięta która kategoria to była "new-nav-v2".

Jak puszczacie flagę bez skrzywdzenia użytkowników?
Nudna sekwencja działa najlepiej.
Puszczcie kod z flagą wyłączoną. Zweryfikujcie, że nic się nie zmieniło.
Włączcie dla własnego zespołu w produkcji. Używajcie przez jeden dzień.
Włączcie dla 1-5% użytkowników, sticky po user ID żeby nikt nie przerzucał między wariantami mid-session.
Obserwujcie wskaźnik błędów, latency i jedną metrykę biznesu. Zdecydujcie próg zanim zaczynacie, nie patrząc na dashboarda.
Podnieście do 100%, czekajcie określony czas, potem usuńcie flagę.
Krok piąty to ten który zespoły pomijają. Dobrze, że dojdziemy do tego dlaczego to kosztuje więcej niż myślicie.
Praktyczna uwaga na temat ewaluacji: ceńcie odczyt flagów tanio i fail-safe. Jeśli serwis flagów nie działa, kod potrzebuje wartości domyślnej. Wybierzcie domyślną na flagi, celowo. Kill switch powinien failować na "bezpieczne", podczas gdy nowa funkcjonalność powinna failować na "off".
Dlaczego feature flagi stają się technical debt?
Każda flaga to fork w kodzie. Dwie flagi robią cztery możliwe ścieżki, dziesięć flag robi 1024, i prawie na pewno przetestowaliście kilka z nich. Engineering guide to flag debt od GrowthBook powołuje się na badania pokazujące że około 75% komponentów toggle były wciąż w codebase do 49 tygodni po wprowadzeniu, choć większość developerów powiedziała że planowała je usunąć.
Hodgson mówi to dobrze w tym samym artykule Fowlera: rozsądne zespoły traktują toggley jako inventory z carrying cost, i pracują żeby to inventory trzymać nisko.
Klasyczna horror story to Knight Capital z 2012. Flaga przemarłej funkcjonalności została ponownie użyta dla nowego zachowania podczas gdy stary kod wciąż siedział na jednym serwerze. Ta niezgodność przyczyniła się do około 460 milionów dolarów straty w poniżej godziny. Wasza stała flaga prawdopodobnie tego nie zrobi. Zrobi coś cichszego: refactor, który łamie gałąź którą nikt nie wiedział że istnieje, lub nowy hire spędzający popołudnie figuring out który z dwóch checkout paths jest rzeczywisty.

Jak znajdujecie każdą flagę w istniejącym repozytorium?
To jest pytanie które docs vendora pomijają, i to jest gdzie większość zespołów się zacinają. Dashboard flag mówi co jest skonfigurowane. Nie mówi gdzie każda flaga jest czytana w kodzie, lub czy ścieżka kodu za flagą "off" jest wciąż osiągalna.
Zacznijcie z tanią metodą:
# każdy literal flag key czytany przez wrapper
rg -n 'isEnabled\("' src/ | sort
# flagi zdefiniowane ale nigdy nie referencjonowane
comm -23 <(jq -r 'keys[]' flags.json | sort) \
<(rg -o 'isEnabled\("([^"]+)"' -r '$1' src/ | sort -u)To rozpada się szybko. Flag keys zbudowane z string concatenation nie pokazują się w grep. Flagi przekazane przez helper functions ukrywają call sites. Monorepo i multi-repo setup mnożą problem, bo ten sam key może być czytany przez trzy serwisy.
To jest gdzie czytanie kodu z toolingiem pomaga. Code search tools, które rozumieją repo mogą odpowiedzieć "gdzie new-checkout jest ewaluowany, i co zależy od wyniku?" w jednym query zamiast pół dnia grep. Cursor i GitHub Copilot radzą to rozumnie w jednym repo. Przez kilka repo potrzebujecie index, który ich obejmuje, który jest case że budujemy codebasechat.
Jak wygląda rozsądny proces czyszczenia flagów?
Traktujcie usunięcie jako część pracy, nie jako zadanie na później.
Utwórzcie ticket usunięcia z flagą. Linkujcie go w opisie flagi. Jeśli ticket nie istnieje, flaga nie wysyła się.
Ustawcie właściciela i datę ważności na każdej non-permanent fladze. Około 90 dni bez zmian to rozsądny trigger dla review.
Usuńcie w dwóch pull requestach. Najpierw usuńcie check flagi i trzymajcie winning path. Potem usuńcie dead branch i jego testy. Małe diffe to reviewable diffe.
Dodajcie time bomb test. Test, który failuje kiedy flaga release przechodzi swoją datę ważności zmienia dobrą intencję w red build.
Ograniczcie total. Jeśli macie 40 aktywnych flag i limit to 40, dodanie jednej oznacza usunięcie jednej.
Static analysis pomaga tutaj też. Tool jak CodeScene może pokazać które pliki przenoszą najbardziej zagmatwaną conditional logikę, która zwykle jest gdzie stare flagi się gromadzą. SonarQube flaguje unreachable i dead code po usunięciu check.
Jak testujecie kod, który siedzi za flagą?
Testing to jest część którą nikt nie budżetuje. Z dwoma ścieżkami na flagi, suite testów potrzebuje pokrycia obu, co najmniej dla flag, które guardy risky behavior.
Trzymajcie to praktyczne. Testujcie on i off states każdej release flagi w testach unit, przez injecting flaga value zamiast czytania live service. Uruchamiajcie jeden end-to-end suite przeciwko domyślnej konfiguracji produkcji, bo to jest co użytkownicy dostają dzisiaj. Potem uruchamiajcie drugi pass z flagą włączoną dla funkcjonalności którą собираетесь release.
Nie próbujcie testować każdej kombinacji. Z dziesięcioma flagami nie możecie. Zamiast tego, trzymajcie flagi niezależne: flaga która zmienia zachowanie tylko kiedy inna flaga jest też on to design smell, i to jest pierwsza rzecz do rozpletania.
Co nowi inżynierowie źle rozumieją na temat flag?
Juniory robią ten sam trzy błędy, i każdy jest tani żeby zapobiec w review.
Nesting flagów. Jedna flaga wewnątrz drugiej tworzy ścieżkę która istnieje tylko kiedy oba są on. Pytajcie zamiast jedną flagę z jasną nazwą.
Logika w nazwie flagi. Klucz jak "show-new-nav-to-premium-users-in-eu" koduje targeting rule którą należy w serwisie flag, nie w stringu.
Zapomniecie domyślnej. Jeśli lookup flagi failuje, co się stanie? Zróbcie autora żeby napisał odpowiedź w opisie pull requesta.
Pierwsze dwa tygodnie nowego hire to dokładnie kiedy biegną w stare flagi bez właściciela. Krótki registry flag, z typem, właścicielem i datą usunięcia dla każdego wpisu, oszczędza kilka godzin pytania wokół.
Kiedy powinniście pokonać feature flagi?
Flagi nie są darmowe, więc pominąć je kiedy:
Zmiana jest mała, reversible i jeden deploy od rollbacku. Flaga dodaje ścieżkę kodu dla no gain.
Zmiana dotyka schema bazy danych w sposób flaga nie może ukryć. Używajcie expand-and-contract migracji zamiast.
Wasz zespół nie ma procesu dla usuwania flag. Naprawcie to najpierw, lub zaciągacie dług na przyszłość readability.
I używajcie je bez wahania kiedy zmiana jest risky, user-facing i hard to reverse przez redeploy. Payment flows, auth changes i nic co ma data migration behind to all qualify.
Co naprawdę byśmy robili w zespole dziesięciu osób
Zacznijcie z booleanem w config i jedną wrapper function, więc każdy read flag przechodzi przez jedno miejsce. Ten pojedynczy choke point sprawia flag list greppable, auditable i łatwy do migracji do hosted service później.
Zaetykietujcie każdą flagę po typie, dajcie jej właściciela i archiwujcie ticket usunięcia w dzień jeden. Przejrzyjcie listę miesięcznie przez dziesięć minut. Usuńcie flagi które były na 100% przez dwa tygodnie.
Feature flag to pożyczka. Weźcie ją kiedy ratuje riskyą release, i zwróćcie ją zanim interest pojawi się w następnym refactor.
Jak wdrażacie nowe inżynierów w temacie flag?
Kiedy nowy junior dołącza do zespołu, nie powinien spędzić pół dnia szukając dokumentacji flag. Utrzymujcie prosty registry - spreadsheet lub dokument - z trzema polami: nazwa flagi, typ, właściciel i data ważności.
To zajmuje 30 minut do ustawienia i oszczędza godziny pytań. Registry w Git gałęzi nie dyskontuje się - flagi żyją w serwisach i konfiguracjach runtime, więc bardziej stabilne miejsce to config management system.
Szczególnie praktyczne: dokumentujcie flag behavior razem z kodem. Komentarz nad instrukcją if (flags.isEnabled()) zmienia znaczenie: przyszli maintainers widzą dlaczego flag istnieje, nie tylko że istnieje.
Skalowanie praktyk flag w rosnącym zespole
W zespole do 5 osób, flagi są proste - wszyscy znają je. W 20 osobach, chaos. W 50, katastrofa jeśli nie macie systemu.
Rozsądny flow: ktoś tworzy flagę w serwisie, automatycznie wysyła notif do Slacka. Co 90 dni, job runuje - lista stałych flag. Zespół przegląda - których nie potrzebujemy. Usunięcie trafia do backlog.
Audyt co miesiąc to nie złoto, ale trzyma to pod kontrolą. Monitorowanie też pomaga - jeśli flaga nie zmienia się przez X dni, alert jej właścicielowi.