Don't break production when you add new features! - Feature Toggles in C#
Tags: csharp, dotnet, programming, tutorial
Published: 2023-02-26 16:00:44

## Problem statement: You broke production after you added a new feature ):

You just added a new feature to your application, it passed all the unit, integration, and E2E testing. It was released and for two weeks, you haven't heard anything bad about it. But now, customers are having a problem with a process that has been working for 5 years without issues. After some digging, you discover that the feature that you added, broke the application if _this_ or _that_ specific state is reached. 

What can you do? A fix would take at least 2 to 3 days to implement and release, but your application is practically unusable for the time being.

## Proposed solution: Feature Toggles

Feature Toggles or Feature Flags is one of many ways to release new features. 

> Feature flags (also commonly known as feature toggles) is a software engineering technique that turns select functionality on and off during runtime, without deploying new code. [1]

In code, they look like this:

```csharp
public void VeryImportantMethod(IFeatureManager featureManager)
{
	if (featureManager.IsEnabled(FeatureToggles.YourNewCoolFeature))
	{
		ExecuteNewFeature();
	}

	ExecuteExistingFunctionality();
}
```

We have a feature manager dependency that will handle whether the feature is enabled or not. The feature manager can take this configuration from settings files, databases, services, etc. 

If your feature needs to be disabled because it breaks existing functionality. You would only need to modify it from your feature toggles source.

One example of a feature toggle source is the Feature Manager in Azure App Configuration:

![edit-feature-flag-expanded](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkkz6qypy9gee9pwqa9h.png)
Image taken from Microsoft Documentation [2].

## Downside of Feature Toggles

There is a big downside to using feature toggles: complexity. [3]

When you add a new feature toggle, you are branching your application execution into a new path that you will need to take into account when you are debugging. And it becomes even more complex when there are feature toggles within feature toggles. 

## Feature Toggles good practices

### The feature toggle manager should not be a concrete object

This goes for all your dependencies in your codebase. The **Dependency Inversion Principle** states that we should depend on abstractions, not concretions. And feature toggles are not the exception. 

Ideally, you should have a static class (or similar depending on your language) with a list of all the feature toggles in your application.

```csharp
public static class FeatureToggles
{
	public const FeatureA;
	public const FeatureB;
	// ...
}
```

And for your feature manager, you need an interface like:

```csharp
public interface IFeatureManager
{
	bool IsEnabled(string featureToggle);
}
```

Then you can inject it into your code:

```csharp
public class CoolClass
{
	private readonly IFeatureManager _featureManager;
	
	public CoolClass(IFeatureManager featureManager)
	{
		_featureManager = featureManager;
	}
	
	public void CoolMethod()
	{
		if (_featureManager.IsEnabled(FeatureToggles.FeatureA))
		{
			ExecuteFeatureA();
		}
	
		ExecuteExistingFunctionality();
	}

	// ...
}
```

This way when you create unit tests, you can mock `IFeatureManager` easily to test your new feature.

You can also implement another `IFeaturesManager` that takes the feature toggles values from another source without affecting existing code.

### In your unit tests, do not check if the feature toggle is enabled or not, mock it!

It is easy to fall into this trap while testing feature toggles:

```csharp
[TestMethod]
public void TestCoolClass()
{
	// Arrange
	IFeatureManager featureManager = new ConcreteFeatureManager();
	CoolClass coolClass = new CoolClass(featureManager);

	// Act
	coolClass.CoolMethod();

	// Assert
	if (featureManager.IsEnabled(FeatureToggles.FeatureA))
	{
		// Assert FeatureA works
	}
	else
	{
		// Assert existing functionality without FeatureA
	}
}
```

This is an anti-pattern in unit testing, we should not have branching logic. Instead, mock the feature manager interface and test both behaviors separately. 

Example using Moq (https://github.com/moq/moq4):

```csharp
[TestMethod]
public void TestFeatureA()
{
	// Arrange
	Mock<IFeatureManager> featureManagerMock = new Mock<IFeatureManager>();
	/// We make sure the feature manager mock returns true when FeatureA is requested.
	featureManagerMock
		.Setup(fm => fm.IsEnabled(FeatureToggles.FeatureA))
		.Returns(true);
	/// We get the mocked interface to pass as dependency.
	IFeatureManager featureManager = featureManagerMock.Object;
	CoolClass coolClass = new CoolClass(featureManager);

	// Act
	coolClass.CoolMethod();

	// Assert FeatureA works as expected
}

[TestMethod]
public void TestExistingFunctionality()
{
	// Arrange
	Mock<IFeatureManager> featureManagerMock = new Mock<IFeatureManager>();
	/// We make sure the feature manager mock returns false when FeatureA is requested.
	featureManagerMock
		.Setup(fm => fm.IsEnabled(FeatureToggles.FeatureA))
		.Returns(false);
	/// We get the mocked interface to pass as dependency.
	IFeatureManager featureManager = featureManagerMock.Object;
	CoolClass coolClass = new CoolClass(featureManager);

	// Act
	coolClass.CoolMethod();

	// Assert existing functionality works as expected
}
```
 
### Have a formal approach to deal with feature toggles

Feature toggles are not meant to be eternal. Once your feature is well tested even in production, you will need to remove the feature toggle from your code, which is sometimes not that straightforward. Your team needs to have a formal approach to remove feature toggles once the feature becomes stable enough.

## References

1. Buchannan, I. (n.d.). _Feature flags_. Atlassian. Retrieved February 24, 2023, from https://www.atlassian.com/continuous-delivery/principles/feature-flags
2. Maud-Lv. (n.d.). _Tutorial: Use azure app configuration to manage feature flags - azure app configuration_. Tutorial: Use Azure App Configuration to manage feature flags - Azure App Configuration | Microsoft Learn. Retrieved February 24, 2023, from https://learn.microsoft.com/en-us/azure/azure-app-configuration/manage-feature-flags
3. Fowler, M. (n.d.). _Feature toggles (aka feature flags)_. martinfowler.com. Retrieved February 24, 2023, from https://martinfowler.com/articles/feature-toggles.html
4. Maud-Lv, M., et al. (n.d.). _Tutorial for using feature flags in a .NET core app_. Tutorial for using feature flags in a .NET Core app | Microsoft Learn. Retrieved February 24, 2023, from https://learn.microsoft.com/en-us/azure/azure-app-configuration/use-feature-flags-dotnet-core?tabs=core5x
5. Farley, D. (2021, January 6). _Continuous integration vs feature branch workflow_. YouTube. Retrieved February 24, 2023, from https://www.youtube.com/watch?v=v4Ijkq6Myfc