Feature enabling when using Branch by Abstraction

Something that I haven't liked for a long time is the use of branches in a projects. I don't like the waste when it comes to merge between branches, "Merge hell". In the beginning of the project I'm in now, it took hours to do merges before a release, both handling conflicts, but also selects different changeset that should include and not include in the merge before a release. The hard part was when a branch per feature was present. Later on this was changed into one single dev branch, but still sometimes two branches may exists. The team was used to work like this from previous projects. To handle this merge hell one dedicated person handle all the merge so the team can work undisturbed (not true, they were involved when conflicts occurs). Even with a dedicated person, the problem still exists, it was just moved. The time it takes to do the merge, was there, the problem with non-disciplines people that did not following the guidelines when it comes to fixing bugs in different branches, or forgot to merge into the main branch, created problems. Wouldn't it be nice to get rid of all the merge problems, let everyone just work in the same branch? There is a way, it may not work for every projects though (sometimes a bigger change may be useful to have in a single branch, but I think it should first be avoided). The solution to the problem is what Paul Hammant calls "Branch by Abstraction".

In short, it's about creating an abstraction over the part of the system that need to be changed, or use an existing abstraction. Implement the new feature side by side with the current production code, and when the new feature is tested and ready for production, switch the old code with the new one, then the old code can be removed. New abstractions added, may also be removed if it's not needed for future use. All code is checked-in into one mainline by everyone in the team. Before a release, a release branch from the mainline is created (used to fix production bugs).

BUT! And it's a BIG but, it requires a lot of discipline among the team members and also a good architecture.

One key "solution" when it comes to work with Branch by Abstraction is to use "feature enabling", to be able to enable features first when it's ready for production.


Feature enabling on an environment level


Visual Studio has support of using compiler directives or build options like Debug and Release etc. I decided to not use those options, instead a flag in a configuration file, the reason is that I want my Continuous Integration still always use a release build, and the deployment of artifacts to the test environment (for the test team) should be in release mode. The same with compiler directives.

Because the build script we use uses XML transforming of configuration files based on the environment it will build and deploy too, I think the configuration file is a good place to add a "featuring enable" switch.

<appSettings>
<add key="FeatureEnableEnvironment" value="development" />
<appSettings>

 

The value of the FeatureEnableEnvironment key in the configuration for the test and development environment is "development". For production it's "production", but this value is ignored. Example of a transforming settings in the configuration file for the production environment:

<appSettings>
<add
key="FeatureEnableEnvironment"
value="production"
xdt:Transform="SetAttributes"
xdt:Locator="Match(key)"/>
</appSettings>

 

The bootstrapper used for configure the object to an IoC Container will read from the setting, and will override the production registration (default registration is for production) with the new object that developers is working on. Here is the bootstrapper for the IoC container, Microsoft Unity 2.0 is used as a IoC contrainer.


public void Configure(IUnityContainer container)
{
RegisterForProduction(container);

if (IsDevelopmentEnvironment())
RegisterForDevelopment(container);
}

private void RegisterForProduction(IUnityContainer container)
{
container.RegisterType<IRejectInvoiceProcess, RejectInvoiceProcess>();
}

private void RegisterForDevelopment(IUnityContainer container)
{
container.RegisterType<IRejectInvoiceProcess, RejectInvoiceProcess_2>();
}

 

When a new feature is under development, an override of the production registration is done within the method RegisterForDevelopment. When the feature is approved for production, the old object will be removed, and the new one will be used instead (probably also be renamed). The override registration in the RegisterForDevelopment will of course also be removed by the team.

Any suggestion and comment of making this even better are welcome, the problem with the blog I use is that there are a lot of spam, so adding a comment to the post will probably disappear among all the spams. So please send med a message on twitter when a comment is added, so I know when to look among all the comments.

If you want to know when I publish a new blog post, feel free to follow me on twitter: @fredrikn

1 Comment

  • We have taken a similar approach in previous projects. In our implementation, the default is 'production'. The code will check the configuration value and if it is MISSING, default to production, otherwise use the value. You can just remove the configuration value using the config transform.

Comments have been disabled for this content.