Co to jest feature flag? Prosty przewodnik dla solo deva
Summary
Feature flag (inaczej feature toggle) to warunek w kodzie, którego wartość kontrolujesz spoza kodu, dzięki czemu funkcję można włączyć lub wyłączyć bez ponownego wdrożenia. Oddziela to wdrażanie od udostępniania: można scalać niedokończoną pracę każdego dnia, wdrażać stopniowo dla 1% użytkowników i mieć natychmiastowy wyłącznik awaryjny. Haczyk: każda flaga dodaje ścieżkę w kodzie i po wdrożeniu trzeba ją usunąć. Solo dev rzadko potrzebuje usługi zewnętrznej od pierwszego dnia.
Co to jest feature flag? To instrukcja if, której odpowiedź znajduje się poza kodem. Nowa ścieżka w kodzie trafia na produkcję wyłączona, a włączasz ją później, zmieniając wartość w pliku konfiguracyjnym, wierszu w bazie danych albo w usłudze flag, bez ponownego wdrożenia. Ten jeden trik oddziela wdrażanie kodu od udostępniania funkcji, dlatego flaga to najtańszy rollback, jaki kiedykolwiek będziesz mieć.
Drugiej połowy tego zdania nauczyłem się na własnej skórze. Moja pierwsza flaga była wartością logiczną w zmiennej środowiskowej, przełączoną w piątkowy wieczór, a potem zapomniałem o jej istnieniu przez jedenaście miesięcy. Nic się nie popsuło. I właśnie w tym tkwi problem, do którego jeszcze wrócimy.
Jak wygląda feature flag w kodzie?
Dużo prostszy, niż sugerują strony główne dostawców. Zdejmij z tego dashboardy, a flaga to odczyt wartości i rozgałęzienie:
const flags = { newCheckout: false };
if (flags.newCheckout) {
return renderNewCheckout(user);
}
return renderOldCheckout(user);Cała reszta to pytanie, skąd bierze się flags i kto może je zmienić. Stała w pliku to flaga, którą zmieniasz przez deploy, a to psuje cały sens. Zmienna środowiskowa zmienia się po restarcie. Wiersz w bazie danych zmienia się w kilka sekund. Usługa hostowana też zmienia się w kilka sekund, a do tego daje targetowanie per użytkownik, interfejs i log zmian.
Problem w praktyce jest taki: sam kod jest banalny, cykl życia już nie. Dwie gałęzie na produkcji to dwa zachowania do przetestowania i dwie ścieżki do debugowania o 2 w nocy, a jedna z nich jest przeznaczona do zgnilizny.

Które z czterech typów flag istnieją i od którego zacząć?
Podział Martina Fowlera w taksonomii feature toggles nadal jest najczystszym sposobem, żeby je uporządkować. Przydatna oś to czas życia każdego typu.
Flagi wydania (release) ukrywają niedokończoną albo ryzykowną pracę. Są tymczasowe: tydzień lub dwa, potem usuwasz. To je potrzebujesz jako pierwsze.
Flagi operacyjne (ops) to wyłączniki awaryjne. Owijasz ciężką albo kruchą funkcję, na przykład widżet rekomendacji czy wywołanie zewnętrznego API, żeby móc ją wyłączyć pod obciążeniem bez deployu. Większość jest krótkotrwała, kilka zostaje na zawsze i to jest w porządku.
Flagi eksperymentów (experiment) dzielą użytkowników na kohorty do testów A/B. Żyją tyle, ile trzeba, żeby uzyskać statystycznie istotny wynik, czyli od godzin do tygodni, i bez realnego ruchu nic nie znaczą.
Flagi uprawnień (permission) bramkują funkcje według planu albo konta: pakiet Pro, grupa beta. Mogą żyć latami, a wtedy przestają być flagami. To uprawnienia i zasługują na porządny model danych.
Jeśli jesteś solo devem z 40 użytkownikami, potrzebujesz flag wydania i może jednego wyłącznika awaryjnego. Flagi eksperymentów na 40 użytkownikach dają szum, a nie dane. Odłóż je, dopóki nie umiesz nazwać metryki i wielkości próby.
Jakie problemy flagi rozwiązują, a gałęzie i deploye nie?
Trzy rzeczy, i tylko te trzy są warte uwagi.
Bezpieczne wysyłanie niedokończonej pracy. Długo żyjące gałęzie są bolesne, bo ich scalanie to mała wojna. Flaga pozwala scalać do main każdego dnia, z nowym kodem uśpionym. To silnik trunk-based development, w którym wszyscy commitują do jednej gałęzi, a flagi niosą części niedokończone.
Stopniowe wdrażanie. Włącz funkcję dla siebie, potem dla 1% użytkowników, potem dla 10%, a na końcu dla wszystkich. Fowler opisuje wybór kohorty kanarkowej mniej więcej 1% przez resztę z dzielenia ID użytkownika przez 100. Jeśli coś jest nie tak, zasięg szkody to garstka osób zamiast całej bazy.
Szybkie cofnięcie. Wycofanie deployu oznacza build, pipeline i trochę odwagi. Przełączenie flagi to jedna edycja. Zły dzień różni się wtedy minutami bólu od godziny.
Żadne z tego nie wymaga usługi zewnętrznej od pierwszego dnia. Wszystko wymaga dyscypliny.
Czy potrzebujesz LaunchDarkly, czy wystarczy plik JSON?
Plik JSON albo tabela w bazie wystarczą, dopóki nie zajdzie jedna z tych rzeczy: nieprogramista musi przełączać flagi, potrzebujesz rollouts procentowych albo targetowania per użytkownik, chcesz ślad audytu, kto co zmienił, albo więcej niż jedna usługa czyta te same flagi.
Oto mniej więcej drabina, na którą wspiąłbym się w tej kolejności:
Stałe i zmienne środowiskowe. Zero kosztów. Wystarczą na pierwszą flagę wydania w projekcie pobocznym.
Tabela
flagsalbo plik JSON czytany w runtime. Dziesięć linijek kodu, natychmiastowe przełączanie, bez dostawcy. Z tym solo projekt dojedzie zaskakująco daleko.Flag service open-source albo hostowany. Gdy chcesz reguł targetowania, stopniowych wdrożeń i interfejsu, z którego skorzysta ktoś inny.
Platforma enterprise. Gdy do gry wchodzą compliance, zatwierdzenia i dziesiątki inżynierów.
Hostowane narzędzia pokrywają kroki 3 i 4. LaunchDarkly to lider rynku z najgłębszymi funkcjami targetowania i zarządzania, a cena to odzwierciedla.
Statsig łączy flagi z eksperymentami i analityką produktową, co ma sens, jeśli chcesz zmierzyć, co flaga zrobiła, a nie tylko ją przełączać.
Pomiń oba, jeśli cały twój zespół to ty. Tabela z trzema kolumnami wygrywa z dashboardem, który otwierasz dwa razy na kwartał. Wybierz usługę dopiero wtedy, gdy ręczna wersja kosztowała cię coś konkretnego, na przykład nocną edycję konfiguracji produkcji, której potem żałowałeś.
Warta znajomości polisa ubezpieczeniowa: OpenFeature to projekt CNCF w inkubacji, który definiuje neutralne wobec dostawców API do ewaluacji flag, z SDK m.in. dla Node.js, Pythona, Go, Javy, .NET i klientów webowych. Piszesz pod standardowy interfejs i podmieniasz providera pod spodem. Jeśli podejrzewasz, że wyrośniesz z pierwszej konfiguracji, podpięcie przez OpenFeature sprawia, że przeprowadzka to zmiana konfiguracji.

Jak dodać pierwszą flagę, nie robiąc bałaganu?
Zacznij od jednej flagi wydania i kilku zasad. To wersja, której sam chciałbym się trzymać wcześniej.
Nazywaj flagę od funkcji, nie od mechanizmu. new-checkout-flow mówi, co się zepsuje, jeśli coś jest nie tak. flag_47 nie mówi nic po sześciu miesiącach.
Domyślnie wyłączona, a wyłączona oznacza stare zachowanie. Konwencja „wyłączona = legacy, włączona = nowe” pozwala rozumować o systemie pod presją. Złam ją, a każda flaga stanie się zagadką.
Ewaluuj w jednym miejscu. Fowler nazywa lekarstwo odwróceniem flagi (toggle inversion): zamiast rozsiewać if (flags.x) po dwudziestu plikach, zdecyduj raz, blisko brzegu systemu, i przekaż wynik dalej. Jeden punkt decyzji to jedno miejsce do zmiany i jedno do testowania.
Napisz ticket na usunięcie w chwili tworzenia flagi. Wrzuć go do backlogu z datą. Fowler sugeruje też daty wygaśnięcia dla krótkotrwałych przełączników, a nawet testy, które wywalają się, gdy flaga przekroczy swoją datę. Flaga bez ticketu na usunięcie to kredyt bez harmonogramu spłat.
Loguj każdą ewaluację, która ma znaczenie. Gdy użytkownik zgłasza buga, chcesz wiedzieć, po której stronie flagi był. Jeśli nie umiesz odpowiedzieć, flaga jest obciążeniem.
Testowanie to miejsce, w którym ludzie przesadzają. Nie musisz testować każdej kombinacji flag, bo większość z nich ze sobą nie współdziała. Przetestuj konfigurację, której oczekujesz na produkcji, przetestuj fallback przy wyłączonej nowej fladze, a opcjonalnie uruchom jeden przebieg z wszystkim włączonym, żeby złapać dryf.
Jaki jest realny koszt flag, o którym nikt nie wspomina?
Każda flaga podwaja ścieżkę w kodzie. Dziesięć niezależnych flag to w teorii 1024 kombinacje. Choć nigdy wszystkich nie przetestujesz, na produkcji możesz trafić na jedną, której nikt nie przewidział.
Bardziej bolesny koszt to martwe flagi. Wdrożenie się kończy, wszyscy są już na nowym zachowaniu, flaga zostaje na 100%, a stara gałąź leży w repo jako kod, którego nikt nie odważy się usunąć. Pół roku później nikt nie pamięta, czy wyłączenie jest bezpieczne.
Najsłynniejsza wersja to Knight Capital, sierpień 2012. Stara flaga, która kiedyś uruchamiała wycofaną funkcję handlową, została ponownie użyta w nowym kodzie. Jeden z ośmiu serwerów nie dostał wdrożenia i dalej działał na starym kodzie. W ciągu 45 minut firma straciła, według własnego raportu kwartalnego, około $440 mln, a późniejsze doniesienia podają bliżej $460 mln.
To firma handlowa z prawdziwymi pieniędzmi i prawdziwymi inżynierami, więc nie będę twierdził, że twój projekt poboczny jest bezpieczniejszy. Lekcja skaluje się w dół bez problemu: nigdy nie używaj ponownie nazwy flagi i usuwaj martwe flagi, zanim staną się archeologią.

Ramka Fowlera, której się trzymam, to traktowanie flag jak inwentarza z kosztem utrzymania. Niektóre zespoły ograniczają liczbę żywych flag i wymagają usunięcia jednej przed dodaniem kolejnej. Dla solo deva twardy sufit pięciu wystarczy.
Kiedy w ogóle pominąć feature flags?
Częściej, niż przyznają dostawcy narzędzi.
Pomiń je, gdy funkcja jest mała, zmianę łatwo cofnąć w gicie, a deploy trwa dwie minuty. Flaga dodaje gałąź, źródło konfiguracji i rzecz do zapomnienia. Jeśli revert jest szybszy niż przełączenie flagi, flaga to teatr.
Pomiń je, gdy nie masz jeszcze użytkowników. Stopniowe wdrażanie dla zera osób to tylko opóźnienie. Wdróż, spójrz w logi, napraw.
Pomiń je przy migracjach bazy, których nie da się cofnąć przełącznikiem. Flaga może ukryć nową kolumnę w UI, ale nie przywróci usuniętej tabeli. Zmiany schematu potrzebują własnego planu expand-and-contract, z flagami albo bez.
Warto je mieć, gdy zmiana dotyka płatności lub autoryzacji, gdy chcesz scalać codziennie z niedokończoną pracą albo gdy zewnętrzna zależność może paść i chcesz mieć wyłącznik awaryjny.
Co obserwować po włączeniu i co zrobić w tym tygodniu?
Flaga kontroluje ekspozycję, a ekspozycja pomaga tylko wtedy, gdy widzisz, co dzieje się dalej. Włączenie funkcji dla 10% użytkowników bez patrzenia na błędy i latencję to rzut monetą z dodatkowymi krokami.
Przed pierwszym wdrożeniem upewnij się, że w mniej niż minutę odpowiesz na trzy pytania: czy błędy wzrosły w kohorcie z flagą, czy latencja się pogorszyła i czy coś zmieniło się po stronie zależności. Monitoring uptime i wyszukiwanie w logach pokrywają większość tego w małym produkcie. Narzędzie takie jak Better Stack trzyma monitory, status page i logi w jednym miejscu, z darmowym planem.
Reguła, której trzymam się teraz: flaga jest warta tyle, ile alarm podpięty do niej. Bez alarmu włączasz rzeczy po ciemku.
W tym tygodniu zrób tak. Wybierz jedną niedokończoną rzecz, której boisz się scalić. Opakuj ją w wartość logiczną czytaną z tabeli albo pliku JSON, domyślnie wyłączoną, i scal do main dziś. Zanim zamkniesz edytor, napisz ticket na usunięcie z datą za dwa tygodnie. Potem włącz ją tylko dla siebie i używaj przez dzień. Jeśli się trzyma, poszerz. Jeśli nie, wyłącz i straciłeś tylko minutę.
Która flaga w twoim kodzie stoi na 100% od ponad miesiąca? To ona będzie pierwszym usunięciem.