Intro

I’m totally in love with the concept of feature toggles. To make a long story short, a Feature Toggle is a strategy used for managing continuous delivery. Thus, it’s an alternative to branching features which can also be slow and error prone.

Domain Model

I declared the interface for requesting a feature. Declaring these interfaces enabled me to define the ubiquitous language for a Feature Toggle.

The following model was implemented:

namespace AppLogic.FeatureToggles

open System.Runtime.CompilerServices

[assembly: InternalsVisibleTo("TestAPI")]
do()

module Client =

    type ClientId = UserId of string

    type ConnectionState = internal Disconnected | Connected
    
    type Feature = 
        | SomeAmazingFeature
        | UnsupportedFeature

    type FeatureToken = internal { Feature : Feature }

    module IO =

        type RequestFeature = ConnectionState -> ClientId -> Feature -> FeatureToken option
        
        module Web =
            type RequestFeature = Feature -> ClientId -> FeatureToken option
        
        module Cache =
            type RequestFeature = Feature -> ClientId -> FeatureToken option

Requesting the feature

I wrote a function that relied on a strategy for retrieving a feature token based on the app’s connection state. Hence, what if the app is offline after launching it? Shouldn’t we still be able to use a feature if it’s available? To address this condition, I declared two interfaces. One interface for web requests and the other for cached values (aka: historical record).

I then mocked-out the request for the feature:

    let requestUsing : IO.RequestFeature =

        fun connection clientId feature ->

            let cached : IO.Cache.RequestFeature =

                fun feature _ ->
                    feature |> function
                    | SomeAmazingFeature -> Some { Feature= SomeAmazingFeature }
                    | UnsupportedFeature -> None
    
            let request : IO.Web.RequestFeature =

                fun feature _ ->
                    feature |> function
                    | SomeAmazingFeature -> Some { Feature= SomeAmazingFeature }
                    | UnsupportedFeature -> None

            connection |> function
            | Connected    -> clientId |> request feature
            | Disconnected -> clientId |> cached  feature

Testing the model

The following are my tests that exercise the model:

module _FeatureToggles.Client

open NUnit.Framework
open FsUnit
open TestAPI.Mock
open AppLogic.FeatureToggles.Client

[Test]
let ``Online: SomeAmazingFeature enabled``() =
    
    (someUserId , SomeAmazingFeature) 
    ||> requestUsing (connectionState())
     |> Option.isSome 
     |> should equal true

[Test]
let ``Offline: SomeAmazingFeature enabled``() =

    (someUserId , SomeAmazingFeature) 
    ||> requestUsing (connectionState'())
     |> Option.isSome 
     |> should equal true

[Test]
let ``Online: SomeAmazingFeature disabled for unsupported feature``() =
    
    (someUserId , UnsupportedFeature) 
    ||> requestUsing (connectionState())
     |> Option.isSome 
     |> should equal false

[Test]
let ``Offline: SomeAmazingFeature disabled for unsupported feature``() =

    (someUserId , UnsupportedFeature) 
    ||> requestUsing (connectionState'())
     |> Option.isSome 
     |> should equal false

Conclusion

In conclusion, I’m totally in love with the concept of feature toggles. As I attempted to explain, a feature toggle is a strategy used for managing continuous delivery. Thus, it’s an alternative to branching features which can also be slow and error prone. I implemented the domain types as well as mocked out the functions that implement the domain interfaces.