Java Feature Toggles – Jakie mają zastosowanie w procesie CI/CD?

/ 16.07.2023 Java

Pracując w stylu outside-in development chcemy jak najszybciej przedstawić funkcjonalność, która jest najbliższa interesariuszom, najczęściej chodzi jakąś makietę UI, pokazującą jak dana funkcjonalność będzie wyglądać z punktu widzenia użytkownika końcowego. Mimo że nie ma tam jeszcze zaimplementowanej domeny, czy bazy danych możemy przedstawić tzw. Walking Skeleton, zawierający podstawowe komponenty systemu. Aby można było to zaprezentować w środowisku stagingowym, a nie produkcyjnym, wykorzystujemy tak zwane feature toggles/flags, czyli przełączniki funkcji. 

Jak wprowadzić możliwość udostępniania funkcji różnym grupom użytkowników bez wdrażania? Czy istnieje sposób na skuteczne testowanie funkcji w środowisku produkcyjnym i natychmiastowe wycofywanie ich w razie potrzeby? Odpowiemy na te pytania, omawiając flagi funkcji lub czasami określane jako przełączniki funkcji. 

Czym są flagi funkcji?  

Przełączniki funkcji, znane również jako flagi, to technika, która pozwala programistom włączać lub wyłączać określone funkcje w aplikacjach bez konieczności wdrażania nowego kodu. Można to zilustrować przykładem, kiedy włączasz światło w domu, nie musisz za każdym razem zmieniać okablowania domu, wystarczy użyć przełącznika i gotowe, a jeśli chcesz je wyłączyć, naciskasz przełącznik ponownie, a światło zgaśnie. Dokładnie to samo dotyczy flag funkcji, pozwalają na wydanie nowej funkcji w oprogramowaniu lub platformie bez przestojów, a zatem można to zrobić w dowolnym momencie, w tym w godzinach pracy.  

Oznacza, że taki przełącznik pozwala wybrać ścieżkę w kodzie w sposób dynamiczny, czy to w momencie budowania, czy uruchamiania produktu, albo w środowisku wykonawczym. Jest to użycie “if” w kodzie, które umożliwia zmianę zachowania kodu, bez jego przepisywania i przetwarzania wszystkiego w potoku wdrażania. 

Jednocześnie ta technika pozwala dużo częściej integrować kod, ponieważ nie wymaga tego, by tkwić na swojej gałęzi funkcji przez kilka tygodni i czekać aż funkcja zostanie w pełni skończona, zanim się zintegruje z resztą kodu. Można niedokończone funkcjonalności łączyć z całą resztą kodu, wrzucać na “MAIN” – główną gałąź kontroli wersji i ten niedokończony kod wrzucić na produkcję (oczywiście tak, żeby tej produkcji nie zepsuć ?). 

flagi funkcji java_1

Zalety flag funkcji 

Flagi funkcji umożliwiają zespołom kontrolę nad wydawaniem funkcji, przeprowadzaniem testów A/B, zarządzaniu długiem technicznym i zapewnieniu płynniejszego wdrożenia. Poniżej główne zalety flag funkcji w kodzie: 

1. Mniejsze ryzyko wdrożenia  

Flagi funkcji dają poczucie bezpieczeństwa psychologicznego, ponieważ wiemy, że w każdej chwili mogę ten przełącznik wyłączyć i tej funkcjonalności nie będzie widział. Zyskujemy odwagę, żeby ten kod dużo częściej integrować i stopniowo wdrażać oraz eksperymentować z różnymi wersjami funkcji. 

2. Szybsze dostarczanie oprogramowania 

Przełączniki umożliwiają testowanie nowych funkcji w środowisku produkcyjnym bez udostępniania ich wszystkim użytkownikom, niezależnie od głównej bazy kodu. 

3. Szybsze uzyskanie informacji zwrotnych 

Dzięki flagom funkcji można zbierać wewnętrzny feedback od moich użytkowników z firmy, nanieść zmiany na niedokończonej funkcjonalności. 

4. Ulepszony proces rozwoju 

Przełączniki funkcji pomagają segmentować użytkowników na podstawie różnych atrybutów, tworzyć i porównywać różne warianty funkcji oraz mierzyć ich wyniki, pomagając zoptymalizować wrażenia użytkownika i cele biznesowe. 

5. Kontrolowanie i monitorowanie 

Flagi określają, kto może uzyskiwać dostęp do funkcji oraz zbierania opinii i danych przed udostępnieniem ich wszystkim. można również używać do stopniowego udostępniania funkcji podzbiorowi użytkowników oraz monitorowania ich wydajności i wpływu. 

6. Szybsze zmiany zachowań, bez konieczności zmian w kodzie źródłowym. 

Przełączniki funkcji pozwalają w dowolnym momencie na zmianę zachowania systemu. Mogą wymagać jedynie ponownego deploymentu, a nawet i ten krok można pominąć w przypadku np. wykorzystania Spring Cloud Config, który pozwoli na zmianę konfiguracji aplikacji, bez negatywnego wpływu na jej dostępność. 

Rodzaje flag funkcji i ich przeznaczenie 

Przełączniki funkcji według Martina Fowlera można sklasyfikować w następujący sposób:  

  • Release toggles — Pozwalają one wdrażać kod, który nie został jeszcze ukończony oraz ukrywać niekompletne funkcje przed użytkownikami.   
  • Experiment toggles — Ten typ jest używany w testach A/B. Najczęściej taka flaga żyje tyle czasu, ile potrzebujemy, aby wyciągnąć wnioski z rezultatów eksperymentu. 
  • Ops Toggles — Głównie służą do kontrolowania aspektów operacyjnych systemu przez osoby zarządzające aplikacją. Można je wykorzystywać do wyłączania pewnych funkcji, które nie są niezbędne do prawidłowego funkcjonowania aplikacji, na przykład.podczas dużego obciążenia serwera. 
  • Permissioning toggles — Ten typ służy do zarządzania funkcjami dostępnymi dla różnych grup użytkowników. Często są stosowane do zarządzania funkcjonalnościami premium i wczesnego dostępu. 
flagi funkcji java_rodzaje

Sposoby wdrażania flag funkcji 

W Javie istnieją różne podejścia do wdrażania przełączania funkcji, w tym przełączniki istniejące w pliku konfiguracyjnym, oparte na bazie danych lub korzystanie z zewnętrznych usług zarządzania nimi. W niektórych przypadkach istnieje dodatkowa aplikacja interfejsu użytkownika z listą funkcji i „przełącznikiem” obok nich. Jeśli flaga znajduje się w pozycji „on”, funkcja będzie dostępna w docelowej aplikacji.  Teraz omówimy zalety i wady tych podejść oraz kiedy ich używać. 

Przełączniki oparte na konfiguracji  

W tym podejściu przełączniki funkcji są zdefiniowane w plikach konfiguracyjnych, takich jak właściwości, YAML lub JSON. Aplikacja odczytuje te pliki konfiguracyjne w czasie wykonywania i włącza lub wyłącza funkcje na podstawie wartości przełączników. 

Zalety: 

  • Przełączniki istniejące w pliku konfiguracyjnym są łatwe do wdrożenia i zrozumienia. 
  • Można zmieniać flagi bez modyfikowania kodu lub ponownego wdrażania aplikacji.  
  • Pliki konfiguracyjne mogą być zarządzane za pomocą systemów kontroli wersji, umożliwiając śledzenie i audyt.  

Wady:  

  • Ograniczona świadomość kontekstu: Przełączniki oparte na konfiguracji zazwyczaj nie obsługują dynamicznego włączania funkcji w oparciu o role użytkowników, uprawnienia lub inne czynniki kontekstowe.  
  • Wraz ze wzrostem liczby funkcji i przełączników, zarządzanie plikami konfiguracyjnymi może stać się wyzwaniem. 

Kiedy używać: Przełączniki oparte na konfiguracji są odpowiednie, gdy potrzebujesz prostego i statycznego sposobu kontrolowania dostępności funkcji, który nie wymaga zmian w czasie wykonywania ani brania pod uwagę kontekstu. 

Przełączniki oparte na bazie danych  

W tym podejściu przełączniki funkcji są przechowywane i zarządzane w bazie danych lub scentralizowanym systemie zarządzania konfiguracją. Aplikacja wysyła zapytanie do bazy danych lub odczytuje konfigurację w czasie wykonywania, aby określić, które funkcje powinny być włączone lub wyłączone.  

Zalety:  

  • Można modyfikować przełączniki w czasie wykonywania, bez konieczności ponownego uruchamiania aplikacji lub zmiany kodu.  
  • Świadomość kontekstu: Przełączniki mogą być powiązane z rolami użytkowników, uprawnieniami lub innymi informacjami kontekstowymi przechowywanymi w bazie danych.  
  • Skalowalność: Scentralizowane przechowywanie pozwala na zarządzanie przełącznikami w wielu instancjach lub środowiskach.  

Wady:  

  • Wdrożenie flag funkcji wymaga dodatkowej infrastruktury, takiej jak baza danych lub system zarządzania konfiguracją.  
  • Częste zapytania do bazy danych mogą obniżać wydajność, zwłaszcza podczas oceny przełączników dla każdego żądania użytkownika.  

Kiedy używać: Przełączniki oparte na bazie danych są przydatne, gdy potrzebna jest dynamiczna kontrola nad dostępnością funkcji, wymagają czynników kontekstowych i chcą uniknąć ponownego uruchamiania aplikacji lub wdrażania kodu w celu modyfikacji przełączników. Są one szczególnie korzystne w aplikacjach na dużą skalę lub systemach rozproszonych.  

Narzędzia zewnętrzne do zarządzania flagami funkcji 

Dostępnych jest kilka rozwiązań do zarządzania flagami funkcji. Istnieje kilka bibliotek SDK dostępnych w Javie, które można wykorzystać do implementacji przełączników funkcji. Biblioteki te oferują różne funkcje, opcje integracji i możliwości zarządzania. Wybierając bibliotekę SDK dla swojego projektu Java, należy wziąć pod uwagę takie czynniki, jak kompatybilność frameworka, wymagania dotyczące zarządzania funkcjami, łatwość użytkowania, czy wsparcie społeczności, aby wybrać tę, która najlepiej odpowiada Twoim potrzebom.  Niektóre z popularnych narzędzi to: 

Togglz 

Plusy: 

  • Lekki i łatwy w użyciu. 
  • Dobrze integruje się z frameworkami Java EE i Spring
  • Zapewnia różne strategie aktywacji przełączników funkcji. 
  • Obsługuje niestandardowe opcje konfiguracji  
  • Ma aktywne wsparcie społeczności i regularne aktualizacje. 

Minusy: 

  • W porównaniu do innych bibliotek ma ograniczone możliwości zaawansowanego zarządzania funkcjami  
  • Ograniczone wsparcie dla zdalnego zarządzania i konfiguracji flagami funkcji. 

FF4J (Feature Flipping for Java) 

Plusy: 

  • Zaawansowane możliwości zarządzania funkcjami, w tym przełączanie oparte na uprawnieniach. 
  • Płynna integracja z  frameworkami Java, takimi jak Spring, CDI i JAX-RS. 
  • Udostępnia konsolę internetową do zarządzania przełączaniem funkcji. 
  • Oferuje różne reguły aktywacji i dezaktywacji dla przełączania funkcji. 
  • Oprogramowanie open-source z aktywną społecznością i regularnymi aktualizacjami. 

Wady: 

  • Dość skomplikowana dokumentacja  
  • Mało elastyczne opcje konfiguracji w porównaniu do innych bibliotek. 

Unleash 

Plusy: 

  • Zaawansowane funkcje przełączania funkcji. 
  • Wiele strategii aktywacji i opcji targetowania. 
  • Scentralizowany serwer zarządzania funkcjami i pulpit nawigacyjny. 
  • Obsługuje aktualizacje konfiguracji w czasie rzeczywistym. 
  • Dobre opcje integracji i wsparcie SDK dla Java. 

Minusy: 

  •  Wymaga zewnętrznej infrastruktury lub usługi, aby w pełni wykorzystać jej możliwości. 

LaunchDarkly 

Plusy: 

  • Kompleksowa platforma zarządzania funkcjami z potężnymi funkcjami przełączania funkcji. 
  • Obsługuje targetowanie oparte na użytkownikach, testy A/B i niestandardowe reguły aktywacji. 
  • Posiada interfejs sieciowy do zarządzania flagami funkcji i konfiguracjami. 
  • Płynna integracja z różnymi frameworkami i usługami programistycznymi. 
  • Zapewnia obszerną dokumentację i zasoby. 

Minusy: 

  • Wymaga subskrypcji w celu uzyskania dostępu do zaawansowanych funkcji i pełnej funkcjonalności. 
  • Cena może mieć znaczenie w przypadku małych projektów lub startupów. 
  • Zależność od usługi innej firmy do zarządzania funkcjami. 

Spring Cloud Config 

Plusy 

  • Centralizacja lokalizacji do zarządzania właściwościami konfiguracji, w tym przełączników funkcji. Ułatwia to aktualizację i utrzymanie flag funkcji w wielu usługach lub instancjach. 
  • Dynamiczne aktualizacje — umożliwiają modyfikację wartości przełączników funkcji w czasie rzeczywistym bez konieczności ponownego uruchamiania lub ponownego wdrażania aplikacji. Ta elastyczność pozwala na szybkie eksperymentowanie i wdrażanie nowych funkcji. 
  • Kontrola wersji — W SCC można śledzić zmiany i w razie potrzeby przywrócić poprzednie wersje, zapewniając lepszą kontrolę nad historią konfiguracji. 
  • Bezpieczeństwo — Spring Cloud Config zapewnia opcje zabezpieczania właściwości przełączników funkcji, poprzez szyfrowanie i mechanizmy kontroli dostępu. Gwarantuje to ochronę przed nieautoryzowanym dostępem. 

Minusy 

  •  Zależność od sieci: Jeśli serwer konfiguracji jest niedostępny, aplikacja może nie być w stanie pobrać zaktualizowanych przełączników, potencjalnie wpływając na zachowanie systemu.   
  • Zwiększona złożoność: Integracja Spring Cloud Config dla przełączników funkcji dodaje dodatkową warstwę złożoności do architektury systemu. Wymaga to zarządzania serwerem konfiguracji, obsługi komunikacji między serwerem a aplikacją oraz zapewnienie spójności między usługami. 

W zależności od potrzeb aplikacji można łączyć powyższe podejścia do wdrożenia przełączników funkcji. Ostatecznie wybór sposobu implementacji flagi w kodzie zależy od takich czynników, jak złożoność aplikacji, wymagany poziom kontroli, potrzeba modyfikacji w czasie wykonywania oraz kompromisy, które chcemy wprowadzić w odniesieniu do zmian kodu, wdrożeń i wydajności. 

Dlaczego rozdzielić wdrożenie od wydania projektu?  

Opcja warunkowa “if” pozwala rozdzielić deployment od releasu ponieważ za tym “if” będzie się kryła informacja, kto tak naprawdę będzie widział daną funkcjonalność, a komu to ukryjemy. 

Dlaczego jest to ważne zrozumieć różnicę między wdrożeniem a wydaniem projektu? 

Powyższe dwie koncepcje różnią się od siebie.  

Deployment, czyli wdrożenie to – wydarzenie techniczne, gdy wprowadzamy zmiany w oprogramowaniu i przerzucamy kod docelowo na środowisko produkcyjne, możemy to wypuścić w dowolnym momencie. 

Release , czyli wydanie to ekscytujacy moment, w którym te nowe funkcje stają się dostępne dla użytkowników końcowych. Tutaj flagi funkcji pozwalają kontrolować wydanie tej nowej funkcji na platformie wdrożeniowej, czyli wybieramy, kto będzie mógł zobaczyć nowe wersje oprogramowania. 

Podsumowując, przełączniki funkcji rozdzielają te dwie funkcje, codziennie możemy wdrażać nowe oprogramowanie, ale teraz możemy podejmować decyzje komu i kiedy pokazujemy nowe wersje. 

Dlaczego flagi funkcji są naprawdę ważne w mechanizmie ciągłego dostarczania i ciągłego wdrażania?  

Flagowanie funkcji umożliwia sprawne wykonywanie CI/CD, pozwalając programistom na częste scalanie ich pracy do współdzielonego repozytorium, bez obawy o zepsucie czegokolwiek lub spowodowanie, że użytkownik końcowy uzyska dostęp do niedokończonych funkcji.  

Przełączniki dają kontrolę nad zachowaniem aplikacji lub platformy, co oznacza, że cały kod jest zawsze wdrażany, ale niektóre gałęzie kodu można testować dla nowych funkcji zmodyfikowanego zachowania, lub go wyłączyć, dopóki nie zostanie włączona flaga. Z kolei za każdym razem, gdy włączasz przełącznik, wtedy ten kod jest dostępny dla użytkowników. 

Testowanie kodu wyposażonego we flagi 

To zależy od strategii testowania, czy to testy jednostkowe, czy manualne itp.  Ważne jest, żeby nie testować każdej możliwej kombinacji flagi funkcji, a przeprowadzać testy tam, gdzie jest prawdopodobieństwo, że coś się wydarzy

Test zakończy się też niepowodzeniem, jeśli funkcja jest obecnie wyłączona. Dlatego najlepiej jest usunąć testy, z głównego przebiegu procesu, dopóki funkcja nie zostanie formalnie wydana. Do tego czasu najlepiej uruchamiać testy tylko wtedy, gdy jest to wymagane i jeśli funkcja została włączona. Po ostatecznym wydaniu funkcji testy można dodać do głównego przebiegu testu. 

Jakie pojawiają się problemy, gdy nie usuniemy flag? 

Sposób zarządzania przełącznikami funkcji pokazuje jakość organizacji. Nieusuwanie flag funkcji po ich zamierzonym użyciu może prowadzić do kilku problemów: 

  • Dług techniczny — Flagi funkcji pozostawione w bazie kodu mogą się z czasem kumulować, co może sprawić, że baza kodu stanie się bardziej złożona i trudniejsza w utrzymaniu, zrozumieniu i debugowaniu.   
  • Zwiększony wysiłek związany z testowaniem i konserwacją — Gdy flagi funkcji nie są usuwane, nadal stanowią część procesu testowania, co oznacza to, że testerzy muszą testować powiązane z nimi ścieżki kodu, nawet jeśli nie są one już istotne.   
  • Zagrożenia dla bezpieczeństwa — Jeśli nieużywane i zapomniane flagi funkcji kontrolują dostęp do wrażliwych funkcji lub ujawniają niezabezpieczoną funkcjonalność, mogą być celem ataku, jeśli nie są odpowiednio zabezpieczone 
  • Spadek wydajności — Flagi funkcji często wiążą się z dodatkowymi kontrolami warunkowymi w kodzie. Jeśli te kontrole nie zostaną usunięte po tym, jak funkcja nie będzie już potrzebna, mogą spowolnić aplikację. 
  • Problemy z kompatybilnością — Flagi funkcji mogą wchodzić w interakcje z innymi częściami bazy kodu, zależnościami lub integracjami.  Obecność nieużywanych flag funkcji może powodować konflikty z innym kodem lub wprowadzać niezamierzone zachowanie. 

 Aby uniknąć tych problemów, konieczne jest rygor inżynierski i trzymanie się ustalonego zestawu praktyk w celu usuwania flag funkcji, gdy spełnią one swoje zadanie. Proces ten powinien obejmować regularne przeglądy kodu, inicjatywy czyszczenia flag i dokumentację, aby zapewnić, że flagi są odpowiednio zarządzane przez cały cykl rozwoju.  

Co się może stać, gdy błędnie wykorzystamy feature flagi? Firma może stracić milliony dolarów dochodu. Tak jak firma  Knights Capital, która straciła 460 milionów dolarów w ciągu 28 minut ?. Więcej o tym przypadku możesz przeczytać tutaj.  

Podsumowanie 

Aby zmaksymalizować korzyści płynące z przełączania funkcji, jednocześnie minimalizując wyzwania i ryzyko, należy zdefiniować cykl życia przełączania funkcji i odpowiednio zarządzać udokumentowanym systemem przełączania funkcji.  

Z pewnością flagi funkcji mogą przynieść wiele korzyści, taki jak rozwój oparty na użytkownikach czy zmniejszanie ryzyka związanego z większymi wydaniami.  

Najważniejsze jest jednak to, by pamiętać, że dobrze przygotowane flagi funkcji muszą być proste w utrzymaniu jako prosty kod i wartości konfiguracyjne. Dlatego zawsze warto się zastanowić nad tym, jaką złożoność wprowadzamy w kod i czy można osiągnąć ten sam wynik w prostszy sposób. 

Kategoria: Java


Mariola Nowak Content Writer
Tomasz Kluza Senior Full-Stack Developer

Design, Development, DevOps czy Cloud – jakiego zespołu potrzebujesz, aby przyspieszyć pracę nad swoimi projektami?
Porozmawiaj o swoich potrzebach z naszymi specjalistami.

Jakub Orczyk

Członek zarządu / Dyrektor sprzedaży
VM.PL

Zamów bezpłatną konsultację
kuba (1)