馃摉 Przegl膮d

Modu艂 Features umo偶liwia zarz膮dzanie feature flags z obs艂ug膮 Firebase Remote Config, percentage rollout i lokalnych overrides do test贸w.

Szybki przyk艂ad
// Definiowanie flag
ADict.Features.define("new_ui", default = false, rolloutPercentage = 50)
ADict.Features.define("max_items", default = 10)

// Sprawdzanie
if (ADict.Features.isEnabled("new_ui")) {
    showNewUI()
}

val maxItems = ADict.Features.getInt("max_items")

馃摑 Definiowanie flag

define(key, default: Boolean, description, rolloutPercentage)

Definiuj flag臋 boolean z opcjonalnym percentage rollout.

define(key, default: String, description, variants)

Definiuj flag臋 string z opcjonalnymi wariantami.

define(key, default: Int, description, range)

Definiuj flag臋 int z opcjonalnym zakresem warto艣ci.

defineLong(key, default: Long, description)

Definiuj flag臋 long.

defineDouble(key, default: Double, description)

Definiuj flag臋 double.

Definiowanie r贸偶nych typ贸w flag
// Boolean z 50% rollout
ADict.Features.define(
    key = "new_checkout_flow",
    default = false,
    description = "Nowy proces checkout",
    rolloutPercentage = 50  // tylko 50% u偶ytkownik贸w
)

// String z wariantami
ADict.Features.define(
    key = "button_color",
    default = "blue",
    variants = listOf("blue", "green", "red")
)

// Int z zakresem
ADict.Features.define(
    key = "max_retries",
    default = 3,
    range = 1..10
)

// Long
ADict.Features.defineLong(
    key = "cache_duration_ms",
    default = 3600000L
)

// Double
ADict.Features.defineDouble(
    key = "discount_rate",
    default = 0.1
)

馃摉 Pobieranie warto艣ci

isEnabled(key: String): Boolean

Sprawd藕 czy flaga boolean jest w艂膮czona (uwzgl臋dnia rollout).

getString(key: String): String

Pobierz warto艣膰 string.

getInt(key: String): Int

Pobierz warto艣膰 int (z walidacj膮 range).

getLong(key: String): Long

Pobierz warto艣膰 long.

getDouble(key: String): Double

Pobierz warto艣膰 double.

馃敡 Overrides (testowanie)

override(key: String, value: Any)

Nadpisz warto艣膰 lokalnie (do test贸w).

clearOverride(key: String)

Usu艅 nadpisanie.

clearAllOverrides()

Usu艅 wszystkie nadpisania.

Testowanie z overrides
// W debug buildzie - wymu艣 w艂膮czenie feature
if (BuildConfig.DEBUG) {
    ADict.Features.override("new_checkout_flow", true)
}

// Reset po testach
ADict.Features.clearAllOverrides()

馃摗 Obserwacja zmian

observe<T>(key: String, listener: (T) -> Unit)

Obserwuj zmiany warto艣ci flagi.

changes: StateFlow<Pair<String, Any?>>

Flow zmian (key to value).

Obserwacja zmian
// Callback
ADict.Features.observe<Boolean>("dark_mode") { enabled ->
    applyTheme(if (enabled) Theme.DARK else Theme.LIGHT)
}

// Flow
lifecycleScope.launch {
    ADict.Features.changes.collect { (key, value) ->
        Log.d("Features", "Flag changed: $key = $value")
    }
}

馃搳 Percentage Rollout

Rollout pozwala w艂膮czy膰 funkcj臋 tylko dla cz臋艣ci u偶ytkownik贸w. Jest deterministyczny - ten sam u偶ytkownik zawsze dostanie t臋 sam膮 warto艣膰.

setUserId(id: String)

Ustaw ID u偶ytkownika dla sp贸jnego rollout.

A/B Testing z rollout
// Ustaw user ID (wa偶ne dla sp贸jno艣ci!)
ADict.Features.setUserId(currentUser.id)

// Definiuj eksperyment - 20% u偶ytkownik贸w
ADict.Features.define(
    key = "experiment_new_onboarding",
    default = false,
    rolloutPercentage = 20
)

// U偶ycie
if (ADict.Features.isEnabled("experiment_new_onboarding")) {
    showNewOnboarding()
    ADict.Analytics.log("experiment_variant", "new_onboarding" to "enabled")
} else {
    showOldOnboarding()
    ADict.Analytics.log("experiment_variant", "new_onboarding" to "control")
}

馃挕 Przyk艂ady praktyczne

Pe艂na konfiguracja
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()

        ADict.init(this, BuildConfig.DEBUG)
        setupFeatureFlags()
    }

    private fun setupFeatureFlags() {
        // UI Features
        ADict.Features.define("dark_mode_enabled", default = true)
        ADict.Features.define("new_navigation", default = false, rolloutPercentage = 30)

        // Limits
        ADict.Features.define("max_downloads", default = 5, range = 1..20)
        ADict.Features.define("cache_size_mb", default = 100)

        // A/B Tests
        ADict.Features.define("checkout_variant", default = "classic",
            variants = listOf("classic", "one_page", "express"))

        // Kill switches
        ADict.Features.define("enable_chat", default = true)
        ADict.Features.define("enable_push", default = true)
    }
}

// U偶ycie w kodzie
fun loadData() {
    val maxItems = ADict.Features.getInt("max_downloads")
    // ...
}

fun showCheckout() {
    when (ADict.Features.getString("checkout_variant")) {
        "one_page" -> showOnePageCheckout()
        "express" -> showExpressCheckout()
        else -> showClassicCheckout()
    }
}