Yesterday I wrote on Feature Flags in a largely language-neutral overview article.
Today I want to discuss my library of choice for Feature Flags in .NET applications: FeatureToggle by Jason Roberts.
Feature Toggle is a very small and dedicated library dedicated to a variety of flexible feature toggle variations.
In Feature Toggle, you define a toggleable feature as a class either extending from a FeatureToggle class such as SimpleFeatureToggle
or the IFeatureToggle
interface.
A simple feature definition would look like this:
public class UseNewAnalyzer : SimpleFeatureToggle
{
}
This feature can then be checked like this:
private static IResumeAnalyzer GetResumeAnalyzer()
{
var useNewAnalyzer = new UseNewAnalyzer();
if (useNewAnalyzer.FeatureEnabled)
{
return new RewrittenAnalyzer();
}
else
{
return new ResumeAnalyzer();
}
}
The code above will look for an entry in the application's configuration file (appSettings.json
, web.config
, or app.config
depending on what type of application is running) and parse that value as a boolean to determine if FeatureEnabled
returns true or false.
A sample .NET Core appSettings.json
file with a feature flag is listed here:
{
"FeatureToggle": {
"UseNewAnalyzer": "true"
}
}
The Design of FeatureToggle
Empty / marker classes and instantiating an object just to check a property on it and throw it away? How could this be a good thing?
Well, it turns out that the reason the code looks like this is that Jason Roberts intentionally designed FeatureToggle to make it hard to make common mistakes associated with feature flags.
Because FeatureToggles will throw exceptions if the configuration setting associated with the toggle doesn't exist, this helps you catch bad application configurations instead of accidentally leaving features offline because a config change never got ported to a new environment.
Additionally, since FeatureToggle uses class names to look up configuration settings, there are no strings lurking in code that might have typos causing the wrong configuration setting to be checked.
This reduces some risks common with other feature flag libraries and that added degree of safety helps code quality and fights environment-specific bugs.
Cleaning up the Sample Code
If the code above is giving you issues, it can be simplified via using a static property like the following:
public class UseNewAnalyzer : SimpleFeatureToggle
{
private static readonly UseNewAnalyzer Instance = new UseNewAnalyzer();
public static bool IsFeatureEnabled => Instance.FeatureEnabled;
}
private static IResumeAnalyzer GetResumeAnalyzer()
{
if (UseNewAnalyzer.IsFeatureEnabled)
{
return new RewrittenAnalyzer();
}
else
{
return new ResumeAnalyzer();
}
}
By using the static getter IsFeatureEnabled
, calling code no longer has to create an instance of the feature class and the code reads a lot more simply. Additionally, you no longer have an empty class due to the static property and instance field.
Different Types of FeatureToggles
FeatureToggle is also designed to be flexible and offer both extensibility via subclassing or using the IFeatureToggle
interface.
For example, I could write an implementation that is only active on the weekends by writing the following:
public class OnlyOnWeekends : IFeatureToggle
{
public bool FeatureEnabled
{
get
{
switch (DateTime.Today.DayOfWeek)
{
case DayOfWeek.Saturday:
case DayOfWeek.Sunday:
return true;
default:
return false;
}
}
}
}
I'm not sure why you'd want this type of a feature toggle, but if you can use the framework to create something simple like this, it can definitely be used to create more advanced things.
The good news is you don't need to create more advanced things. FeatureToggle ships with a number of built in implementations:
- SimpleFeatureToggle - The example we've worked with up until this point. It reads a value from a configuration file.
- EnabledOnOrAfterDateFeatureToggle - A feature that is only available once a date has been reached. This can be used as a 'go live' date.
- EnabledOnOrBeforeDateFeatureToggle - A feature that is only available before a date has been reached. This can be used as a retirement date.
- EnabledBetweenDatesFeatureToggle - A feature that is only available between two dates
- EnabledOnDaysOfWeekFeatureToggle - A feature that is only available on certain days of the week.
- AlwaysOnFeatureToggle - Designates a feature that will always be activated no matter what. This can be used to migrate away from configuration management without ripping out the class entirely.
-
AlwaysOffFeatureToggle - Similar to
AlwasOnFeatureToggle
, but will never be active. -
HttpJsonFeatureToggle - This makes a HTTP GET request to a location configured in the feature's configuration file and expects a result like
{"enabled": true}
, then parses thatenabled
value to determine if the feature is enabled. Bear in mind that this will be a synchronous web call and prone to errors due to network, internet, and firewall issues. - SqlFeatureToggle - Using this, you would define both a connection string in your configuration as well as a SQL query that returns a single boolean value. This value is then the return value for whether the feature is enabled or not. Again, this is a synchronous operation that is prone to more errors than many of the other implementations.
- EnabledOnOrAfterAssemblyVersionWhereToggleIsDefinedToggle - Checks the current assembly version against one defined in the configuration file and activates the feature if the configured version has arrived. This can be used for planning features to go live with major release numbers without knowing the date those releases will ship
FeatureToggle is obviously very well equipped to deal with most basic needs and simple and extensible enough to be able to adapt to any custom needs you encounter.
If you'd like to learn more about FeatureToggle, check out the GitHub repository and give the library a try.
If you want more learning material, watch Jason Robert's awesome Pluralsight course. This is how I first found out about the library and it's very interesting to watch an instructor give a course on a library they created.
Cover Photo by Kari Shea on Unsplash
Top comments (6)
Not related to the post itself, but how did you implement the '3 part series' thing. I'm guessing it's a funky Markdown feature that I just can't find documented, and you haven't manually just created these tables?
Dev.to automatically does that if you define a series fir multiple articles that share the same name. It's cool, but you can't customize it too much.
How have you defined it as a series? I initially thought it would be a tag, but it's clearly not.
If you're in editor version 2, you click the ... to get the popup with the cannonical URL and series name. Give it a series name. With editor v1, you can set a front matter attribute for the series name.
Thanks!
I never realised there were two versions of the editor! (If anyone's reading this and, like me, can't find it, it's under settings -> misc).
It looks like once you've created your post you're stuck in the version of the editor that you created it is (at least I don't get the fancy new screen when I edit old posts!)
I'm now going to create everything as a series! :-)
Cool! This seems like a good overview of how this library works.
I like Jason Roberts' content on Pluralsight and he seems to have made a real pragmatic library here.
One way I've avoided "scattered strings" used for config is to use the
nameof()
operator.This helps keep the value directly tied to the field.
I still have reservations about using a concretion directly, especially a volatile one (it depends on environment specific config) that is new'd up outside the composition root.
This complicates unit testing, effectively requiring integration tests for this section of code.
That said, direct access to feature state/status is easier to understand and requires less architecture.
👍