Skip to content

Commit

Permalink
Renamed Feature to FeatureSwitch.
Browse files Browse the repository at this point in the history
  • Loading branch information
timscott committed Feb 21, 2012
1 parent 75fac11 commit a6a2dd9
Show file tree
Hide file tree
Showing 15 changed files with 65 additions and 64 deletions.
24 changes: 12 additions & 12 deletions README.markdown
Expand Up @@ -4,7 +4,7 @@ FlipIt is a feature flipper. It provides a simple and flexible way to flip feat

The essence of FlipIt can be seen in this interface.

public interface IFeature
public interface IFeatureSwitch
{
bool IsOn(IFeatureSettingsProvider featureSettingsProvider);
}
Expand All @@ -17,9 +17,9 @@ Scenario: Flip a feature `ON` and `OFF` for everyone all the time.

Create a feature.

public class MyFeature : BooleanFeature
public class MyFeatureSwitch : BooleanFeatureSwitch
{
public MyFeature() : base("my_feature_enabled") { }
public MyFeatureSwitch() : base("my_feature_enabled") { }
}

Use it anywhere in your app to conditionally enable the feature.
Expand All @@ -35,7 +35,7 @@ Use it anywhere in your app to conditionally enable the feature.

public void DoSomething()
{
flipper.DoIfOn(new MyFeature(), () =>
flipper.DoIfOn(new MyFeatureSwitch(), () =>
{
//do the feature
});
Expand All @@ -58,9 +58,9 @@ Scenario: Roll out a feature region by region. (Send notifications to delivery

Create the feature.

public class SendInRouteNotificationsFeature : ListFeature<int>
public class SendInRouteNotificationsFeatureSwitch : ListFeatureSwitch<int>
{
public SendInRouteNotificationsFeature(Region region) : base(
public SendInRouteNotificationsFeatureSwitch(Region region) : base(
settingName: "region_ids_with_in_route_notifications_enabled",
isOnFunc: ids => ids.Contains(region.Id)) { }
}
Expand All @@ -80,8 +80,8 @@ Use it.
{
//do stuff

var notifyFeature = new SendInRouteNotificationsFeature(evt.Order.Destination.Region);
if (flipper.IfOn(notifyFeature))
var switch = new SendInRouteNotificationsFeatureSwitch(evt.Order.Destination.Region);
if (flipper.IfOn(switch))
{
//do it;
}
Expand Down Expand Up @@ -113,7 +113,7 @@ In the preceding examples we satisfy dependencies using constructor injection. F

Use the built in static class instead of providing an instance via the constructor. But don't blame us when your code is hard to unit test.

Flipper.DoIfOn(new MyFeature(), () =>
Flipper.DoIfOn(new MyFeatureSwitch(), () =>
{
//do the feature
});
Expand All @@ -128,9 +128,9 @@ Code that implements features should be "closed for modification" after flipping

## Making Features

In the usage examples we create features using the base classes `BooleanFeature` and `ListFeature<T>`. There's `Feature<T>` too. These are nice, but you don't have to use them. It's easy to create features from scratch that do anything you can imagine.
In the usage examples we create features using the base classes `BooleanFeatureSwitch` and `ListFeatureSwitch<T>`. There's `FeatureSwitch<T>` too. These are nice, but you don't have to use them. It's easy to create features from scratch that do anything you can imagine.

public class CoinTossFeature : IFeature
public class CoinToss : IFeatureSwitch
{
public bool IsOn(IFeatureSettingsProvider featureSettingsProvider)
{
Expand All @@ -152,4 +152,4 @@ Create your own implementation of `IFeatureSettingsProvider`. For example, you m

## Missing Settings

All of the built-in Feature classes use settings to flip features. They treat a feature as `ON` if a setting is missing (by looking at the Missing property). The reason is simple: features tend to move from `OFF` to permanently `ON`. We don't want a bunch of old settings hanging around. So when we're done flipping a feature, we can just remove the setting and leave the code alone.
All of the built-in FeatureSwitch classes use settings to flip features. They treat a feature as `ON` if a setting is missing (by looking at the Missing property). The reason is simple: features tend to move from `OFF` to permanently `ON`. We don't want a bunch of old settings hanging around. So when we're done flipping a feature, we can just remove the setting and leave the code alone.
Binary file modified package/FlipIt.0.1.0.0.nupkg
Binary file not shown.
3 changes: 2 additions & 1 deletion publish.bat
Expand Up @@ -3,6 +3,7 @@ setlocal
:PROMPT
SET /P AREYOUSURE=Are you sure (Y/[N])?
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END
tools/nuget.exe push package/Catnap.0.1.0.0.nupkg
tools\nuget.exe push package\FlipIt.0.1.0.0.nupkg
:END
pause
endlocal
18 changes: 9 additions & 9 deletions src/FlipIt.Tests/FeatureFlipperSpecs.cs
Expand Up @@ -6,48 +6,48 @@ namespace FlipIt.Tests
public abstract class behaves_like_feature_flipper_spec
{
protected static FeatureFlipper flipper;
protected static TestFeature feature;
protected static TestFeatureSwitch featureSwitch;

Establish context = () => flipper = new FeatureFlipper(new NullFeatureSettingsProvider());
}

public abstract class behaves_like_feature_flipper_spec_where_test_feature_is_on : behaves_like_feature_flipper_spec
{
Establish context = () => feature = new TestFeature(true);
Establish context = () => featureSwitch = new TestFeatureSwitch(true);
}

public abstract class behaves_like_feature_flipper_spec_where_test_feature_is_off : behaves_like_feature_flipper_spec
{
Establish context = () => feature = new TestFeature(false);
Establish context = () => featureSwitch = new TestFeatureSwitch(false);
}

public class when_checking_if_an_on_feature_is_on : behaves_like_feature_flipper_spec_where_test_feature_is_on
{
static bool result;
Because it = () => result = flipper.IsOn(feature);
Because it = () => result = flipper.IsOn(featureSwitch);
It should_return_true = () => result.Should().Be.True();
It should_call_feature_is_on = () => feature.TimesIsOnWasCalled.Should().Equal(1);
It should_call_feature_is_on = () => featureSwitch.TimesIsOnWasCalled.Should().Equal(1);
}

public class when_checking_if_an_off_feature_is_on : behaves_like_feature_flipper_spec_where_test_feature_is_off
{
static bool result;
Because it = () => result = flipper.IsOn(feature);
Because it = () => result = flipper.IsOn(featureSwitch);
It should_return_false = () => result.Should().Be.False();
It should_call_feature_is_on = () => feature.TimesIsOnWasCalled.Should().Equal(1);
It should_call_feature_is_on = () => featureSwitch.TimesIsOnWasCalled.Should().Equal(1);
}

public class when_doing_if_an_on_feature_is_on : behaves_like_feature_flipper_spec_where_test_feature_is_on
{
static bool didDo;
Because of = () => flipper.DoIfOn(feature, () => { didDo = true; });
Because of = () => flipper.DoIfOn(featureSwitch, () => { didDo = true; });
It should_do_action = () => didDo.Should().Be.True();
}

public class when_doing_if_an_off_feature_is_on : behaves_like_feature_flipper_spec_where_test_feature_is_off
{
static bool didDo;
Because of = () => flipper.DoIfOn(feature, () => { didDo = true; });
Because of = () => flipper.DoIfOn(featureSwitch, () => { didDo = true; });
It should_do_action = () => didDo.Should().Be.False();
}
}
2 changes: 1 addition & 1 deletion src/FlipIt.Tests/FlipIt.Tests.csproj
Expand Up @@ -55,7 +55,7 @@
<Compile Include="FeatureFlipperSpecs.cs" />
<Compile Include="FlipperSpecs.cs" />
<Compile Include="NullFeatureSettingsProvider.cs" />
<Compile Include="TestFeature.cs" />
<Compile Include="TestFeatureSwitch.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
Expand Down
10 changes: 5 additions & 5 deletions src/FlipIt.Tests/FlipperSpecs.cs
Expand Up @@ -6,27 +6,27 @@ namespace FlipIt.Tests
{
public class beahves_like_flipper_spec
{
protected static TestFeature feature;
protected static TestFeatureSwitch featureSwitch;

Establish context = () =>
{
FlipItConfig.FeatureSettingsProvider = new NullFeatureSettingsProvider();
feature = new TestFeature(true);
featureSwitch = new TestFeatureSwitch(true);
};
}

public class when_checking_if_flipper_feature_is_on : beahves_like_flipper_spec
{
static bool result;
Because of = () => result = Flipper.IsOn(feature);
Because of = () => result = Flipper.IsOn(featureSwitch);
It should_return_true = () => result.Should().Be.True();
It should_call_feature_is_on = () => feature.TimesIsOnWasCalled.Should().Equal(1);
It should_call_feature_is_on = () => featureSwitch.TimesIsOnWasCalled.Should().Equal(1);
}

public class when_doing_flipper_feature_is_on : beahves_like_flipper_spec
{
static bool didDo;
Because of = () => Flipper.DoIfOn(feature, () => { didDo = true; });
Because of = () => Flipper.DoIfOn(featureSwitch, () => { didDo = true; });
It should_do_action = () => didDo.Should().Be.True();
}
}
@@ -1,13 +1,13 @@
using FlipIt.Features;
using FlipIt.Settings;
using FlipIt.Switches;

namespace FlipIt.Tests
{
public class TestFeature : IFeature
public class TestFeatureSwitch : IFeatureSwitch
{
private readonly bool isOn;

public TestFeature(bool isOn)
public TestFeatureSwitch(bool isOn)
{
this.isOn = isOn;
}
Expand Down
6 changes: 3 additions & 3 deletions src/FlipIt/FeatureFlipper.cs
@@ -1,6 +1,6 @@
using System;
using FlipIt.Features;
using FlipIt.Settings;
using FlipIt.Switches;

namespace FlipIt
{
Expand All @@ -18,12 +18,12 @@ public FeatureFlipper(IFeatureSettingsProvider featureSettingsProvider)
this.featureSettingsProvider = featureSettingsProvider;
}

public bool IsOn<T>(T feature) where T : IFeature
public bool IsOn<T>(T feature) where T : IFeatureSwitch
{
return feature.IsOn(featureSettingsProvider);
}

public void DoIfOn<T>(T feature, Action action) where T : IFeature
public void DoIfOn<T>(T feature, Action action) where T : IFeatureSwitch
{
if (IsOn(feature))
{
Expand Down
8 changes: 4 additions & 4 deletions src/FlipIt/FlipIt.csproj
Expand Up @@ -38,8 +38,9 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Features\BooleanFeature.cs" />
<Compile Include="Switches\BooleanFeatureSwitch.cs" />
<Compile Include="FeatureFlipper.cs" />
<Compile Include="Switches\FeatureSwitch.cs" />
<Compile Include="Settings\AppSettingsFeatureSettingsProvider.cs" />
<Compile Include="Settings\FeatureListSetting.cs" />
<Compile Include="Settings\FeatureSetting.cs" />
Expand All @@ -48,10 +49,9 @@
<Compile Include="Flipper.cs" />
<Compile Include="IFeatureFlipper.cs" />
<Compile Include="Settings\IFeatureSettingsProvider.cs" />
<Compile Include="Features\IFeature.cs" />
<Compile Include="Switches\IFeatureSwitch.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Features\Feature.cs" />
<Compile Include="Features\ListFeature.cs" />
<Compile Include="Switches\ListFeatureSwitch.cs" />
<Compile Include="Settings\ThreadSafeCache.cs" />
<Compile Include="Settings\ICache.cs" />
</ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions src/FlipIt/Flipper.cs
@@ -1,5 +1,5 @@
using System;
using FlipIt.Features;
using FlipIt.Switches;

namespace FlipIt
{
Expand All @@ -21,7 +21,7 @@ static Flipper()
/// <typeparam name="T">The type of the feature.</typeparam>
/// <param name="feature">The feature.</param>
/// <returns>Whether the feature is OFF or ON.</returns>
public static bool IsOn<T>(T feature) where T : IFeature
public static bool IsOn<T>(T feature) where T : IFeatureSwitch
{
return flipper.IsOn(feature);
}
Expand All @@ -32,7 +32,7 @@ static Flipper()
/// <typeparam name="T">The type of the feature.</typeparam>
/// <param name="feature">The feature.</param>
/// <param name="action">The action to perform if the feature is ON.</param>
public static void DoIfOn<T>(T feature, Action action) where T : IFeature
public static void DoIfOn<T>(T feature, Action action) where T : IFeatureSwitch
{
flipper.DoIfOn(feature, action);
}
Expand Down
6 changes: 3 additions & 3 deletions src/FlipIt/IFeatureFlipper.cs
@@ -1,5 +1,5 @@
using System;
using FlipIt.Features;
using FlipIt.Switches;

namespace FlipIt
{
Expand All @@ -11,14 +11,14 @@ public interface IFeatureFlipper
/// <typeparam name="T">The type of the feature.</typeparam>
/// <param name="feature">The feature.</param>
/// <returns>Whether the feature is OFF or ON.</returns>
bool IsOn<T>(T feature) where T : IFeature;
bool IsOn<T>(T feature) where T : IFeatureSwitch;

/// <summary>
/// Perform the specified action if the feature is On.
/// </summary>
/// <typeparam name="T">The type of the feature.</typeparam>
/// <param name="feature">The feature.</param>
/// <param name="action">The action to perform if the feature is ON.</param>
void DoIfOn<T>(T feature, Action action) where T : IFeature;
void DoIfOn<T>(T feature, Action action) where T : IFeatureSwitch;
}
}
@@ -1,14 +1,14 @@
using FlipIt.Settings;

namespace FlipIt.Features
namespace FlipIt.Switches
{
/// <summary>
/// A base class that provides a terse way to create IFeatures that are based on a simple boolean settings.
/// A base class that provides a terse way to create IFeatureSwitches that are based on a simple boolean settings.
/// </summary>
public abstract class BooleanFeature : Feature<FeatureSetting<bool>, bool>
public abstract class BooleanFeatureSwitch : FeatureSwitch<FeatureSetting<bool>, bool>
{
/// <param name="settingName">The name of the setting.</param>
protected BooleanFeature(string settingName) : base(settingName, v => v) { }
protected BooleanFeatureSwitch(string settingName) : base(settingName, v => v) { }

protected override FeatureSetting<bool> GetFeatureSetting(IFeatureSettingsProvider featureSettingsProvider)
{
Expand Down
@@ -1,15 +1,15 @@
using System;
using FlipIt.Settings;

namespace FlipIt.Features
namespace FlipIt.Switches
{
/// <summary>
/// Base class for a feature. Uses a setting to flip a feature.
/// Base class for a feature switch. Uses a setting to flip a feature.
/// </summary>
/// <typeparam name="T">The type of the value of the setting used to decide whether the feature is OFF or ON.</typeparam>
public abstract class Feature<T> : Feature<FeatureSetting<T>, T>
public abstract class FeatureSwitch<T> : FeatureSwitch<FeatureSetting<T>, T>
{
protected Feature(string settingName, Func<T, bool> isOnFunc) : base(settingName, isOnFunc) { }
protected FeatureSwitch(string settingName, Func<T, bool> isOnFunc) : base(settingName, isOnFunc) { }

protected override FeatureSetting<T> GetFeatureSetting(IFeatureSettingsProvider featureSettingsProvider)
{
Expand All @@ -18,18 +18,18 @@ protected override FeatureSetting<T> GetFeatureSetting(IFeatureSettingsProvider
}

/// <summary>
/// Base class for a feature that uses a list setting to flip a feature.
/// Base class for a feature switch that uses a list setting to flip a feature.
/// </summary>
/// <typeparam name="T">The setting used to decide whether the feature is off or on is a list. This is the item type of that list.</typeparam>
/// <typeparam name="TFeatureSetting">What kind of setting the feature uses.</typeparam>
public abstract class Feature<TFeatureSetting, T> : IFeature where TFeatureSetting : FeatureSettingBase<T>
/// <typeparam name="T">The setting used to decide whether the feature is OFF or ON is a list. This is the item type of that list.</typeparam>
/// <typeparam name="TFeatureSetting">What kind of setting the feature switch uses.</typeparam>
public abstract class FeatureSwitch<TFeatureSetting, T> : IFeatureSwitch where TFeatureSetting : FeatureSettingBase<T>
{
protected readonly string settingName;
protected readonly Func<T, bool> isOnFunc;

/// <param name="settingName">The name of the setting.</param>
/// <param name="isOnFunc">The function used to decide if the feature is OFF or ON. The input parameter is the setting value.</param>
protected Feature(string settingName, Func<T, bool> isOnFunc)
protected FeatureSwitch(string settingName, Func<T, bool> isOnFunc)
{
this.settingName = settingName;
this.isOnFunc = isOnFunc;
Expand Down
@@ -1,11 +1,11 @@
using FlipIt.Settings;

namespace FlipIt.Features
namespace FlipIt.Switches
{
/// <summary>
/// An interface for features.
/// An interface for feature switches.
/// </summary>
public interface IFeature
public interface IFeatureSwitch
{
/// <summary>
/// Whether the feature is OFF or ON.
Expand Down

0 comments on commit a6a2dd9

Please sign in to comment.