Skip to content

Instantly share code, notes, and snippets.

@camshaft
Last active December 14, 2015 02:39
Show Gist options
  • Save camshaft/5015469 to your computer and use it in GitHub Desktop.
Save camshaft/5015469 to your computer and use it in GitHub Desktop.
other experiment ideas
/**
* Module dependencies
*/
var express = require("express")
, experiments = require("./experiments");
var app = module.exports = express();
/**
* Features
*/
// Defaults to [true, false]
experiments.feature("validate");
// Multi-variant
experiments.feature("loginButtonColor", ["red", "blue", "green", "yellow"]);
/**
* Configure our app
*/
app.configure(function(){
app.use(experiments);
});
app.get("/", function(req, res, next){
res.render("view");
});
app.get("/ad-hoc", function(req, res, next) {
// We can do ad-hoc features
res.feature("welcomeMessage", ["message1", "message2"], function(err) {
if(err) return next(err);
if(res.features.validate) {
// Our validate feature is turned on
}
else {
// It's turned off
}
res.render("view");
});
});
/**
* Module dependencies
*/
var pivot = require("pivot");
/**
* Expose experiments
*/
var experiments = module.exports = pivot();
/**
* Store the user's enabled features
*/
experiments.serialize(function(features, req, res, next){
res.cookie("pivot", JSON.stringify(features));
next();
});
/**
* Get the enabled features for the user
*/
experiments.deserialize(function(req, res, next){
next(null, JSON.parse(req.cookies.pivot));
});
/**
* Gives the user object to pivot
*/
experiment.findUser(function(req, res, next){
next(null, req.user);
});
/**
* Retrieve feature settings from our backend
*
* This can be anything:
* * JSON file
* * API Call (i.e. Product owner service)
* * DB Call
*
* These should really be separate modules so you can have pluggable backends to do this stuff
*/
experiments.lookup(function(){
var features = {};
/**
* @param {String} name
* @param {Array[String]} variants
* @param {Function} done
*/
return function(name, variants, done){
/**
* We can do a few things here:
* * Lookup our feature settings locally
* * If we dont have it, notify the admin control panel page
* * Log outdated features; either ones that should be integrated or ones that should be removed
*/
// In this case we'll just look it up locally
// This should also look up if the variants have changed
if(features[name]) {
done(null, features[name]);
}
else {
var feature = features[name] = {};
variants.forEach(function(variant) {
// Give it an equal split by default (expects 0 to 1)
feature[variant] = 1/variants.length;
// We could also give it a list of groups
// feature[variant] = ["beta", "admins"];
// or just a single group
// feature[variant] = "beta";
});
done(null, features[name]);
}
};
})());
/**
* Tells pivot which variant gets assigned to the user
*
* @param {String} feature
* @param {Object} variants
* @param {Object} user
* @param {Function} done
*/
experiments.assign(function(feature, variants, user, done){
/**
* If the variant is a group, we can inspect the `user` object to check where they fall
* If the variant is a weight, we can implement our own random assignment algorithm
*
* The callback expects the name of the variant chosen for the given user
*/
// For this example we're just going to assign the first variant to everyone
done(null, Object.keys(variants)[0]);
});
<h1>
<% switch(features.welcomeMessage){ %>
<% case "message1": %>
"Welcome!"
<% break; %>
<% case "message2": %>
"Hey there Friend!"
<% break; %>
<% } %>
</h1>
<div class="login">
<button class="btn btn-<%= features.loginButtonColor %>">Login</button>
</div>
<div class="login" data-pivot="'loginButtonColor'">
<button data-pivot-vary="'red'" class="btn btn-red">Login</button>
<button data-pivot-vary="'blue'" class="btn btn-blue">Login</button>
</div>
@camshaft
Copy link
Author

The only view engines that would work with this setup are async ones

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment