Feature Flipping
Dependency :
compile ":feature-flipper:0.3.2"
Summary
Description
Description
The feature-flipper plugin provides a mechanism to turn features on and off within a grails application. It is inspired by Flikr's 'flipping out' work in this space to do the same, and the implementation is quite similar.This is foundational if you want to support a Continuous Deployment strategy and need to move unreleased features, or un-tested code into a production environment, but want to turn it off. It also allows you to do A/B testing if you choose by turning certain features on for certain users, while leaving it off for everyone else.Currently, the plugin provides the ability to set features per server and per roles if you so desire, or you can use the same configuration files across all servers.Features
- Configuration is stored within an XML file at the application root or at a location you define (don't worry, you don't need to know the XML, its just a way to persist the state).
- You can have per-environment configurations. So that you can have all the features on while you develop and selected features on in production.
- Adds a convenience method to all Controllers and Services called hasFeature() that can test whether a feature is enabled for the current app
- Also provides a Tag library to do the same, and allows you to test whether features are available in GSPs
- A FeatureFlipper service is also provided so that you administer your features (UI for this is coming)
- Features are read from the XML file on startup and stored in the ServletContext
- When editing features (CRUD), they are updated in the ServletContext as well as persisted to the XML file
- NEW (+) - Now supports groovy ConfigSlurper Style files
Configuration
To get started, you install the plugin;grails install-plugin feature-flipper
featureFlipper.flipperConfigPath = 'path/to/config/file.groovy'
environments {
production {
featureFlipper.flipperConfigPath = 'path/to/config/file.groovy'
}
}Example: Using it in your Code & Deploying
When you are ready to start introducing new features, you first decide what you want to call the feature. For the sake of this example, lets say you want to introduce a feature that enables users to invite their friends, and you want to introduce it to users that have the role ROLE_BETA and want to deploy it to one of your servers in your cluster. Lets call this feature "InviteFriends"You simply go ahead and write your code in your controllers and services as you normally would, and wrap anything that you want to switch on/off with an if statement like so;if (hasFeature("InviteFreinds", ["ROLE_BETA"])) { //add your code that supports Invite Friends functionality }
<ff:hasFeature name="InviteFriends" roles="${["ROLE_BETA"]}"> //your code </ff:hasFeature>
Deploying
To deploy, you simply configure the features and deploy the XML with the application to the servers. Because config files can be different per server, you have quite a bit of flexibility.Some Notes about the methods and tags
The hasFeature() method that is available in all controllers and methods, has two signatures;- hasFeature(featureName) : here you simply pass the featureName, and it will pass true if the feature is enabled, or it will also pass true if the feature is yet to be defined (this is so you can develop without worrying about it configuration)
- hasFeature(featureName, Roles (+)) : This is as above, but allows you to pass an Array of Roles. Note that this is security library agnostic, and simply assumes you that no matter what security method you are using, you are able to pass the current user's Roles as an Array.
- Pass no attributes : Will always evaluate to true
- Pass the name of the feature as name="" : will test whether that feature is enabled or not
- Pass the name and the roles as roles="${ (+)}" : will test whether the feature is enabled and for the roles passed as per the above method.
Customising your Config
Although you don't really have to mess with the Config Files, you can do and its quite simple. The FeatureFlipperService typically manages this, but there are some times that you may want to manually set this up. There are two options with the files. Version 0.1 of the plugin uses an XML config file, while Version 0.2 now also supports a ConfigSlurper style config files (recommended).ConfigSlurper Style
features=[ [ "name":"FeatureName", "description":"Feature Description", "active":true, "roles":[] ], [ "name":"OtherFeature", "description":"Other Feature Description", "active":false, "roles":[] ] ]
XML Style
The schema is;<features>
<featureitem>
<name>NameOfFeature</name>
<description>Description of the Feature</description>
<active>true</active>
<roles>
<role>ROLE_USER</role>
<role>ROLE_ADMIN</role>
</roles>
</featureitem>
<featureitem>
.....
</featureitem>
</features>- NAME : THe name of the feature, this should contain no spaces and only letters, and is what is passed in the methods and tag above as the feature name
- DESCRIPTION : Something descriptive to help you know what the feature is
- ACTIVE : Boolean true/false
- ROLES : An array of ROLE, if any match, and the feature is enabled, it will pass true
- ROLE : A string ROLE
FeatureFlipper Service
Additionally, you have a FeatureFlipperService that allows you to manage the features. Typically, you would use this in the controller that would be used to manage the features. It has the following functions;- listFeatures() : returns all features as an array of Feature Objects
- getFeature(featureName) : returns a single Feature Object for the given name
- setFeature(feature) : either updates (if the name exists) or creates a new feature (if the name doesn't exist and is unique) in the list of available features, and updates the XML file. 'feature' is a Map Object that contains; String name, String description, Boolean active, Array of Strings roles.
- removeFeature("featureName") : removes the feature with the given name from the list of available features and updates the XML file
Future Plans
This should be a good start, but the following is planned for the future;- script to auto generate Admin screens to manage features
- Support for persisting Features in JSON format to file and Database