How it works
The feature toggles are stored in a static class. What? A static class?!? I don't like it! Bear with me. I thought the same when I first heard the idea but I was convinced otherwise. This static class is used purely to store the values of the toggles, that's it. This comes with a few significant benefits. Primarily it can be defined in a common project (our solution has a lot of projects) and then be used anywhere, view, service, or controller. In addition it doesn't need to be passed around via constructor injection so it doesn't pollute a huge number of classes in the code base. Just to highlight that point, there is absolutely zero IoC setup required to use toggles once the initial implementation is done. But wait, there's more good stuff. What about unit tests? Will adding feature toggles break them? Nope. Because the static class is just a container the toggles will default to being off. If you want to create unit tests which test the toggle being on, just set the toggle to true in the unit test. Easy.
So how is it populated? It's very simple. A new Action Filter is applied to all controllers. For our code this is very easy because all controllers inherit from a base class. On every page load this Action Filter retrieves the toggle values from the database, if they have changed.
Why get toggles from the database? There are a few good reasons. Firstly it's very easy to change their value at run time. Secondly it's very easy to make them available to every project in a solution. This is in contrast to a previous mechanism I tried whereby the toggles were stored in appSettings in a web.config file which required the adding of a file attribute to the appSettings element in each project where the toggles were required. Another benefit of using database toggles is that the implementation can easily be extended. It would be fairly easy to add new features like toggles controlled by date or toggle state. E.g. Always on, always off.
Are there any disadvantages to this approach? Currently because the toggles are populated by an Action Filter they can only be used in MVC applications, not windows services or console applications etc.
FeatureToggles static class
Each feature toggle is simply a public static boolean with a private setter. Why a private setter? It indicates to others using that class that they shouldn't change the value of an individual toggle variable. However there does need to be a mechanism for setting toggle values for unit testing purposes, which is done by SetToggleValue. Reflection is used to prevent the need for any extra code being written when a toggle is added.
SetFeatureToggles is used to populate all the toggles using reflection. Again reflection means no code changes are required when adding or removing toggle variables. The toggle name passed in must match the name of the toggle variable. Note, the FeatureToggle classes passed into the method simply contain two properties, string Name and bool IsActive.
GetActiveFeatureTogglesAsStringForBodyTag returns a string containing a space separated list of toggle variable names prefixed with "FT_" which is outputted in the class attribute of the body tag in each page. This allows CSS rules to be defined for when the toggle is on.
HasBeenInitalised is required to ensure the toggle values are retrieved from the database the first time the application is run. This is a quirk of our implementation because the cache isn't necessarily invalidated when the application is restarted.
The job of this Action Filter is very straight forward. If the toggles have changed retrieve the values from the database and repopulate the static toggle variables. This avoids reloading the toggles on every page load. I'm not showing the implementation details of FeatureToggleService because it's very specific to our application. There's nothing special going on to be honest. GetAll() simply returns a list of FeatureToggle classes either from the cache, if populated, or the database. The FeatureToggle class has two properties, string Name and bool IsActive. HaveValuesChanged() unsurprisingly returns a bool indicating whether the toggle values have changed.
How to add a toggle
To start using a feature toggle only one step is required. Add a public static boolean property to FeatureToggles class.
Obviously the toggle will always be false until you also add the toggle to the database. This is done using a simple admin tool which can add, remove or flip toggles. Whenever one of these actions is taken the cache is cleared which will cause the static toggle values to be refreshed.
Programmatically hide or show a feature:
Or use the outputted CSS class:
- Incredibly easy to add a new toggle
- Incredibly easy to use a toggle in any layer of the application
- Easy to extend the implementation. E.g. Add date after which toggle is active
- Existing unit tests are not broken
- Toggles can be flipped easily at run time with no need to manually edit a config file
- No IoC set up required
- Toggles can incorporate CSS
- Only works in MVC projects
- Some people won't like the static class implementation