Jak wykorzystać feature flags, żeby zyskać większą kontrolę nad aplikacją?

Jak wykorzystać feature flags, żeby zyskać większą kontrolę nad aplikacją?
Chyba każdy, kto zajmuje się budową oprogramowania może opowiedzieć kilka historii o niedziałających funkcjach. Starannie tworzymy aplikacje z niewielkich elementów, stosujemy zaawansowane wzorce architektury, ale i tak czasem coś odmawia posłuszeństwa. Skutkuje to błędami, a nawet awarią systemu. Wtedy sytuację może uratować feature toggling. Sprawdź, jak wdrożyć feature flags i zwiększ stabilność swojej aplikacji.

Czym jest feature toggling?

W najprostszym ujęciu feature toggles (nazywane także feature flags) to przełączniki typu włącz/wyłącz, które pozwalają nam dynamicznie aktywować i dezaktywować poszczególne elementy systemu. I to nawet jeśli jest on już w danym momencie uruchomiony.

Cały koncept jest dość prosty – aplikacja (albo system) komunikuje się z innym serwisem, który decyduje, czy dana funkcja powinna być aktywowana, czy nie.

I co dalej? Na tej podstawie aplikacja może np. pokazywać użytkownikowi określony zestaw przycisków albo je przed nim ukrywać. Może też wyświetlać okienko pop-up z informacją, że dana funkcja jest aktualnie niedostępna.

Jakie korzyści daje feature toggling?

Feature toggles to sprawdzone rozwiązanie, często stosowane podczas tworzenia oprogramowania. Ale dlaczego warto poświęcić trochę czasu na wdrożenie go i utrzymywanie? Wyróżniliśmy kilka ważniejszych powodów:

1. Większa kontrola nad oprogramowaniem
Kiedy dochodzi do awarii systemu, problematyczny element należy dezaktywować, ale pozostałe części mogą nadal pracować. W ten sposób zapewniamy użytkownikowi lepsze doświadczenia, niż gdybyśmy zablokowali cały system i pokazali jedynie ekran z komunikatem błędu.

2. Uproszczona integracja procesu wdrażania pomiędzy back-endem a front-endem
Aplikacje klienckie mogą być publikowane bez konieczności stawiania wcześniej back-endu. Te funkcje, które nie są jeszcze wspierane przez back-end, można ukryć dzięki feature toggles i dezaktywować, dopóki nie zostaną wdrożone po obu stronach.

3. Łatwiejsze dotrzymywanie terminów cyklu publikacji
Zazwyczaj opóźnienia wynikają z faktu, że niektóre funkcje nie są dokończone lub nie działają prawidłowo. To sprawia, że trzymanie się planu staje się naprawdę trudne. Dzięki feature toggles, kiedy dochodzi do takiej sytuacji nadal możemy opublikować aplikację na czas i po prostu dezaktywować wybrane części, dopóki nie będą gotowe.

4. Publikacje dla wybranych grup użytkowników
Niektóre funkcje mogą być aktywowane tylko dla poszczególnych frakcji albo grup użytkowników. Dzięki temu możemy analizować, jak dana funkcja wpływa na biznes i w jaki sposób jest postrzegana przez odbiorców. To może stać się źródłem wielu wartościowych informacji i ułatwiać przeprowadzanie testów A/B, tym samym wspomagając rozwój naszej aplikacji.

Powyższe argumenty dowodzą, że feature toggles to rozwiązanie, z którego wszyscy mogą czerpać profity – końcowi użytkownicy, firma, a także sami twórcy oprogramowania.

Definiowanie wartości feature flags

Wdrażanie feature flags w aplikacjach mobilnych może być naprawdę proste, pod warunkiem, że wiemy, których narzędzi używać i jakimi zasadami się kierować podczas konfiguracji.

Poniżej wypisaliśmy najważniejsze zasady definiowania feature toggles:

  • Prostota – toggle nie powinien być niczym więcej niż tylko przełącznikiem włącz/wyłącz, który opisuje pojedynczą funkcję albo grupę funkcji. Bardziej złożone rozwiązania mogą wprowadzać niepotrzebne zamieszanie wraz ze wzrostem liczby feature toggles.
  • Odświeżanie danych i usuwanie pamięci podręcznej – często chcemy, żeby ostatni stan naszych feature toggles został zapamiętany i zapisany z myślą o użytkowaniu aplikacji offline. Ale zależy nam również na tym, żeby stany funkcji od czasu do czasu automatycznie się odświeżały . Dzięki temu aplikacja ma dostęp do aktualnych stanów toggli.
  • Możliwość nadpisywania wartości – powinniśmy zapewnić rozwiązanie, które pozwoli zmieniać stan feature toggles na życzenie. To ułatwia programowanie i testowanie. Zaufaj nam, zespół QA będzie Ci wdzięczny!

Mając w pamięci te wytyczne, możemy zacząć wdrażanie feature toggles w naszej aplikacji.

Jak wdrożyć feature flags?

Źródła feature flags

Przede wszystkim musimy zdefiniować, gdzie chcemy przechowywać informacje o stanach feature toggles. Naturalnym wyborem wydaje się Firebase Remote Config, zwłaszcza, że i tak większość aplikacji mobilnych korzysta z Firebase’a. Ale nie jest to jedyne rozwiązanie – każda baza danych typu key-value powinna się sprawdzić. Jeśli chcemy, możemy nawet wykorzystać REST API i pobierać toggle z naszego własnego serwera.

Remote Config daje jednak dostęp do takich korzyści i benefitów, jak:

  1. Oficjalne, natywne SDK dla Androida, iOS-s i Fluttera.
  2. Możliwość przechowywania pliku (XML na Androidzie; Plist na iOS-ie) z domyślnymi wartościami, które mogą być wykorzystane w momencie, kiedy aplikacja nie jest w stanie pobrać danych z serwera.
  3. Definiowanie różnych wartości w zależności od ustalonych warunków, co jest przydatne np. wtedy, gdy chcemy aktywować jedną funkcję na Androidzie, a dezaktywować ją na platformie iOS.

Jeśli szukasz szczegółowych instrukcji instalacji, najlepiej skorzystaj z dedykowanych przewodników dla Androida i iOS-a.

Dodawanie parametrów w Remote Config

Webowy UI Firebase’a oferuje zestaw kontrolek i pozwala zdefiniować klucz oraz opis dla każdej wartości.

 

Domyślne wartości mogą zawierać jakiekolwiek dane typu JSON, ale w naszym przypadku wystarczą zwykłe wartości boolean. Po dodaniu parametru możemy opublikować zmiany, a nasz Remote Config będzie natychmiast dostępny dla serwisów klienckich.

Określanie warunków dla feature flags

Kiedy dodajemy parametr, Firebase pozwala nam ustawiać różne wartości w zależności od ustalonych warunków.

Zestawy warunków mogą stanowić dodatek do analityki albo grup określonych przez Firebase Analytics. Mogą one również być uzupełnione o dedykowane wartości zdefiniowane w Firebase.

Przykładowo, możemy ustanowić wartość warunkową wyłącznie dla urządzeń z systemem Android:

Feature flags: Defining a new condition for parameters

W podobny sposób możemy ustawić taki sam rodzaj warunku na urządzenia iOS. To pozwala nam aktywować dane funkcje na tylko jednej platformie:

Adding a parameter key only for Android platform

Korzystanie z feature flags na Androidzie

Kiedy nasza instancja Firebase Remote Config jest już gotowa, możemy przystąpić do wdrażania wsparcia dla niej w aplikacjach na Androida i iOS-a.

W tym artykule bierzemy na warsztat Androida i Kotlina, ale cała procedura jest niemal identyczna w przypadku iOS-a i Swifta.

Pobieranie wartości feature flags

Zanim zaczniemy korzystać z feature flags, musimy pobrać Remote Config. Dzięki temu otrzymamy aktualne wartości z Firebase. Zazwyczaj taka operacja ma miejsce tylko raz, w momencie uruchamiania aplikacji. Zalecamy jednak zapoznanie się ze Strategiami ładowania Firebase Remote Config, żeby zobaczyć również inne możliwe rozwiązania.

Cały proces jest dokładnie udokumentowany w przewodnikach na Androida i iOS, dlatego uznaliśmy, że pominiemy tę część w naszej instrukcji.

Definiowanie modelu danych funkcji

Dla każdej funkcji musimy zdefiniować pole „klucz”. Podana wartość musi pasować do klucza przechowywanego w Remote Config. Dobrym pomysłem jest też dodanie polecenia fetchImmediately. To wartość typu boolean, która określa, czy Remote Config należy odświeżać przed sprawdzeniem stanu funkcji, czy nie.

enum class Feature(
	val key: String,
	val fetchImmediately: Boolean = false
) {
	FLAG_TEST(
    	key = "feature_flag_test",
    	fetchImmediately = false
	),
	DEPENDING_ON_PLATFORM(
    	key = "feature_depending_on_platform",
    	fetchImmediately = true
	)
}

Implementacja feature flag checks

Feature flags łatwo sprawdzimy, tworząc prosty interfejs. Wystarczy do tego jedna metoda:

interface FeatureManager {
	suspend fun isEnabled(feature: Feature): Boolean
}

Prawidłowa implementacja powyższego interfejsu musi opierać się na danych z Remote Config, uwzględniając nasz parametr fetchImmediately.

Przykład poniżej powinien sprawdzić się w większości przypadków, ale jeśli jest taka konieczność, możemy dodać też inne funkcje.

class RemoteFeatureManager : FeatureManager {
	// Instance of remote config, probably best to inject it using DI
	// In order to make testing easier
	private val remoteConfig = Firebase.remoteConfig.apply {
    	// Attaching default values from XML file
    	setDefaultsAsync(R.xml.remote_config_defaults)
    	// In this block additional parameters can be configured
    	setConfigSettingsAsync(remoteConfigSettings {
        	minimumFetchIntervalInSeconds = 300
    	})
	}

	override suspend fun isEnabled(feature: Feature): Boolean {
    	// Refreshing remote config depending on fetchImmediately value
    	// If needed, additional check can be added to check if config fetch was successful
    	if (feature.fetchImmediately) remoteConfig.fetchAndActivate().await()
    	// Returning remote config value assigned to feature key
    	return remoteConfig.getBoolean(feature.key)
	}
}

W celach związanych z debugowaniem i testowaniem możemy wykorzystać osobne instancje Firebase’a z różnymi wartościami Remote Config albo nadpisać je lokalnie.

Tę ostatnią opcję wdrożymy z łatwością dzięki SharedPreferences. Trzeba tylko ustawić funkcje jako domyślnie aktywne i dodać jedną więcej metodę do zmiany stanów feature toggle. Później może ona być dostępna z ekranu debugowania albo poprzez plugin służący do testów QA (sugerujemy Hyperion). W ten sposób będziemy szybko przełączać wartości, gdy zajdzie taka potrzeba.

class LocalFeatureManager(context: Context) : FeatureManager {
 
	companion object {
  	const val FEATURE_PREFERENCES_NAME = "feature_flags"
	}
 
	// Instance of shared preferences instead of remote service
	private val sharedPreferences = context.getSharedPreferences(
        	FEATURE_PREFERENCES_NAME,
        	Context.MODE_PRIVATE
	)

	// Value is read from SharedPreferences, and enabled by default
	override suspend fun isEnabled(feature: Feature): Boolean {
    	return sharedPreferences.getBoolean(feature.key, true)
	}
 
	// Can be used to turn features on and off from
    fun setFeatureState(feature: Feature, isEnabled: Boolean) {
  	  	sharedPreferences.edit()
        	.putBoolean(feature.key, isEnabled)
        	.apply()
	}
}

Biorąc pod uwagę fakt, że wszystkie te implementacje stanowią dodatek do standardowego interfejsu, możemy też ustawić opcję, która pozwala na przełączanie się pomiędzy nimi w określonym miejscu w aplikacji. Dzięki temu zespół QA będzie korzystać zarówno ze zdalnych, jak i lokalnych zestawów feature flags, w zależności od potrzeb.

 

Feature flags pozwalają budować stabilniejsze systemy modularne z dodatkowym mechanizmem awaryjnym, który przydaje się, gdy coś nie działa zgodnie z planem. Oczywiście, to rozwiązanie sprawia, że kod jest bardziej złożony i występują w nim dodatkowe warunki, które wymagają sprawdzania. Często jednak okazuje się, że rezultat wart jest wysiłku. Feature toggles są niezwykle użyteczne zwłaszcza wtedy, gdy liczba funkcji rośnie. Warto dać im szansę!

 

Wycena projektu

Sprawdź, jak wykorzystujemy naszą wiedzę w praktyce i stwórz z nami swój projekt.

Dlaczego warto rozwijać z nami projekty?

Logo Mobile Trends Awards

Mobile Trends Awards 2017

Nominacja w kategorii
M-COMMERCE

17

opinii klientów

Clutch logo
Logo Legalni bukmacherzy

Nagroda Legalnych Bukmacherów 2019

Najlepsza aplikacja mobilna

60+

zrealizowanych projektów