How many times do you find yourself near the software release finish line on an exciting new feature only to be pulled off by management in the last minute to sneak in some higher priority emergency fix? What do you do with the unfinished feature’s code if parts of it were already functional and merged into master? Do you pluck it out and move to a remote feature branch? Do you simply comment out the code not ready for exposure to the customer? What about some of the nice software design improvements that were done as part of the feature and are being put to good use by the team today? Do you also put design improvements off till the feature is deemed by management high priority again?
These questions typically get decided on by the team on a case by case basis, and often with big compromises affecting both project delivery and code quality.
While consulting for Sears in 2009 and working at Groupon.com in 2012, I happened to work in teams that adopted a very effective and inexpensive solution to the problem called “Branch by Abstraction“, a technique originally popularized by Martin Fowler, author of UML Distilled and Patterns of Enterprise Application Architecture.
In this talk, I aim to explain Branch by Abstraction and demonstrate how to apply in Ruby using a gem I wrote called Abstract Feature Branch, partly inspired by the internal team libraries used at Sears and Groupon. The gem has already had over 50,000 downloads from rubygem.org and has been utilized in several of my newer projects, including launch of EarlyShares.com and enhancements of Factor75.com.
Attendees should walk out with basic understanding of Branch by Abstraction and enough knowledge of Abstract Feature Branch to be able to explore further in their own projects after the talk.
3. Problem
● Developer merged into master functional
code for an unreleased feature.
● Manager pulls developer off of feature just
prior to release to work on emergency fix
● What does Developer do with merged code?
4. Problem
● Alternative 1 - Delete code and re-add later
○ PURE INSANITY!!!
● Alternative 2 - Comment code out in place
○ Results in dead code that might be way out of date
and non-functional once enabled again
● Alternative 3 - Move code to a feature branch
○ Expensive and can cost the team a lot more in
merging back later on
○ Loses the team any benefits in code design
improvements that came from feature
5. Solution
Branch By Abstraction using Ruby gem: github.
com/AndyObtiva/abstract_feature_branch
“A lesser-known source-control best practice I’ve been pushing for
a number of years is “Branch by Abstraction”. It is not my invention, and
has been best practice for many years, but how about it is given a
name. The suggestion is that you can convene large sets of developers
in a single trunk (Trunk Based Development) and avoid “short lived
feature branches” that you have to merge back. The problem being with
feature branches is that the current state of any one of them might be
unable to be deployed for a number of weeks while the team gets it
right. Those branches just end up running and running ….”
- Paul Hammant
7. Solution Code - Declarative
feature_branch :feature_auto_signup do
# perform logic
end
8. Solution Code - Imperative
if feature_enabled?(:feature_auto_signup)
# perform logic
else
# perform alternate logic
end
9. Run-time En/Disable
● Enabling a new feature at run-time with environment variables:
ENV['ABSTRACT_FEATURE_BRANCH_FEATURE_AUTO_SIGNUP']='true'
● Disabling a buggy recently deployed feature without a redeploy:
ENV['ABSTRACT_FEATURE_BRANCH_FEATURE_AUTO_SIGNUP']='false'
10. Heroku
● Enabling a new feature at run-time without a redeploy:
heroku config:add
ABSTRACT_FEATURE_BRANCH_FEATURE_AUTO_SIGNUP=true -
a heroku_application_name
● Disabling a buggy recently deployed feature without a redeploy:
heroku config:add
ABSTRACT_FEATURE_BRANCH_FEATURE_AUTO_SIGNUP=false
-a heroku_application_name
11. Per User Feature Enablement
● AbstractFeatureBranch allows enabling
features per user
● Users can be configured in a Redis table
● That allows runtime enablement of features
for users
12. Summary of Benefits
● Ensure integration of upcoming features into
the main code base to avoid major
integration issues and delays down the road
● Avoid managing an unwieldy number of
Git/Hg feature branches
● Toggle features at Run-time or deploy-time
based on business needs, including web
routes, CSS, and JS includes if needed.
13. Recommendation
● To keep the code-base clean, have an
expiration policy to pluck out feature
declarations after 2 months of each feature
release (except when Business knows they
want to delay a feature till later)
● In web apps, make sure to wrap routes
declarations with abstract feature branching
logic too for security purposes
14. Alternatives
● Ruby gems like Flipper or Rollout
○ Do not support simple config via yaml files
○ Might be overkill for smaller projects
○ Quite useful for bigger ones, albeit solving a different
problem (gradual roll-out, a/b testing, and
multivariate testing)
● Actual Feature Branching (e.g., via Git)
○ Simpler when the scope of change is contained
within 1 or 2 weeks of work only