Using prefs to override feature variables
This page details adding pref-key
to a feature definition. This cause the FML generated code to check the user preferences (UserDefaults
or SharedPrefences
) before checking the Nimbus configuration store or the default.
Setting up
The app's preferences object needs to be added to the NimbusBuilder
call:
- Swift
- Kotlin
NimbusBuilder()
.with(userDefaults: UserDefaults.standard) // or alternative
.build(…)
Without this line, the default value used is UserDefaults.standard
.
NimbusBuilder(context).apply {
sharedPreferences = … // the shared preferences being used for this app
}
.build(…)
Without this line, the default value used in null
, and this feature will not function.
These should be readable by Nimbus, but writeable by the rest of the app. For best effect, these should be the same preferences that drive the Settings screens.
Once the preference object is available to nimbus, you can add pref-key
s to feature variables.
Adding a pref-key
to a feature variable definitions
The pref-key
can be specified by top level feature variables:
features:
sample-feature:
variables:
is-enabled:
type: Boolean
default: false
pref-key: sample-feature.isEnabled
The generated API is used in the same way as without the pref-key
:
- Swift
- Kotlin
let feature = FxNimbus.shared.features.sampleFeature.value()
if feature.isEnabled {
// Do something because the feature has been enabled.
}
val feature = FxNimbus.features.sampleFeature.value()
if (feature.isEnabled) {
// Do something because the feature has been enabled.
}
However, now, the call to feature.isEnabled
is overridden by the preference held at sample-feature.isEnabled
.
This is available for types that are supported by preferences: Boolean
, Int
, String
and Text
.
Generated code sketch
The generated code looks approximately like:
- Swift
- Kotlin
let isEnabled: Boolean {
return prefs.getBoolean("sample-feature.isEnabled") ??
json.getBoolean("is-enabled") ??
defaults.isEnabled
}
Without the pref-key
:
let isEnabled: Boolean {
return json.getBoolean("is-enabled") ??
defaults.isEnabled
}
val isEnabled: Boolean =
prefs.getBoolean("sample-feature.isEnabled") ?:
json.getBoolean("is-enabled") ?:
defaults.isEnabled
Without the pref-key
:
val isEnabled: Boolean =
json.getBoolean("is-enabled") ?:
defaults.isEnabled
Limitations
This is available for feature variables (not nested Objects
fields), and only for scalar types.
It is not available for structural types (i.e. Option<T>
, List<T>
or Map<String, T>
).
If there is demand for it, then support for these types and places will be considered.
Similarly, we're looking for feedback on how to make this API or generated code better.
Additional effects of experiment events
If the user sets any of the named preferences for the feature, then the feature is said to be user-modified.
This is exposed in the isModified()
method of the feature.
User-modified features will not emit exposure events.
Question: Should user-modification be allowed for the general population? i.e. can we add these toggles to a public facing settings screen?
Answer: Currently, it is recommended that user-modification should be exposed only in Secret Settings screens.
This is not suitable as building an opt out of all experiments involving the feature.