Skip to content

Instantly share code, notes, and snippets.

@redhead
Last active June 14, 2022 14:19
Show Gist options
  • Save redhead/9ed3b48d50843f16ac76b18d08c07e99 to your computer and use it in GitHub Desktop.
Save redhead/9ed3b48d50843f16ac76b18d08c07e99 to your computer and use it in GitHub Desktop.
Kotlin Context Receivers allow nice Feature Toggles
// client code
object NewFeature : Feature
object NewFeatureVariant : Feature
fun main() {
// configuration
val featureConfiguration = mapOf(
NewFeature to true,
NewFeatureVariant to true
)
val featureFlagContext = object : FeatureFlagContext {
override fun isFeatureEnabled(feature: Feature): Boolean {
return featureConfiguration[feature] ?: false
}
}
// service bean creation (could be a @Bean method)
val serviceA =
with(featureFlagContext) { // provide the context
createServiceA()
}
// invocation
serviceA.doAStuff()
}
context(FeatureFlagContext)
fun createServiceA(): A {
val newA = NewA()
val oldA = OldA()
return object : A {
override fun doAStuff(): Boolean {
return whenFeatureOnOrElse(
NewFeature,
{ newA.doAStuff() },
{ oldA.doAStuff() }
)
}
}
}
interface A {
fun doAStuff(): Boolean
}
context(FeatureFlagContext)
class NewA : A {
override fun doAStuff(): Boolean {
if (NewFeatureVariant.isEnabled()) {
println("Feature variant 2 enabled")
} else {
println("Feature variant 1 enabled")
}
return true
}
}
class OldA : A {
override fun doAStuff(): Boolean {
println("Old impl")
return false
}
}
// infrastructure code
interface Feature {
val name: String
get() = this.javaClass.simpleName
}
interface FeatureFlagContext {
fun isFeatureEnabled(feature: Feature): Boolean
}
// utility method to switch behavior on feature on/off
context(FeatureFlagContext)
fun <T> whenFeatureOnOrElse(feature: Feature, bodyEnabled: () -> T, bodyDisabled: () -> T): T {
return when {
isFeatureEnabled(feature) -> bodyEnabled()
else -> bodyDisabled()
}
}
// utility method to nicely get feature state
context(FeatureFlagContext)
fun <T : Feature> T.isEnabled(): Boolean {
return isFeatureEnabled(this)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment