Random Cookie Maker

Sounds like a delicious treat. I could go for a random cookie right about now.

While I’m on the topic of sharing little helper classes I’ve written, here’s another.

I often create code that represents an untested concept. Actually, half the time I author code for the purpose of testing a concept. Anyway, testing something on the front end usually means showing it to a limited group of folks and that means I have to have a way to consistently show that group the thing I’m testing.

I took a few messy lines of code that I’d been re-using over and over and made a tidy class out of it:

var rndCookieMaker = Class.create();
rndCookieMaker.prototype = {
	limit: 10,
	days: 999,
	initialize: function(args) {
		this.cookieName = args.cookieName;
		if (this.isset(args.limit)) this.limit = args.limit;
		if (this.isset(args.days)) this.days = args.days;
		if (this.isset(args.domain)) this.domain = domain;
		this.verify();
	},
	isset: function(val) {
		if (typeof val == "undefined") return false;
		return true;
	},
	verify: function() {
		this.val = getCookie(this.cookieName);
		if (this.val == null || this.val == "" || parseInt(this.val) == "NaN") {
			this.val = this.makeRand();
			this.saveVal();
		}
	},
	saveVal: function(val) {
		if (this.isset(val)) this.val = val;
		if (this.isset(this.domain)) setCookie(this.cookieName, this.val, this.days, this.domain);
		else setCookie(this.cookieName, this.val, this.days);
	},
	makeSeed: function() {
		today=new Date();
		seed = (today.getTime()*9301+49297) % 233280;
     return seed/(233280.0);
	},
	makeRand: function() {
     return Math.ceil(this.makeSeed()*this.limit);
	}
};

This class (rndCookieMaker) basically gives your users a random number between 1 and the ceiling you pass in and cookies them with it. If they already have a cookie, it just retrieves that value.

So let’s say you want to show your test to 10% of the audience. You’d instantiate the above class thusly:

var randCookieExample = new rndCookieMaker({cookieName:"testNumber1", limit: 10, days: 60});

(you can also pass in domain: if you want)

This will create an object that has .val = the random number for that user, up to (and including) the number 10, and will expire in 60 days. Note that it has dependencies on the rather generic classes getCookie and setCookie:

//generic cookie setter
function setCookie(name,value,days,domain) {
  if (days) {
    var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString();
  } else expires = ""; var cookieVal = name+"="+value+expires+"; path=/"; if (typeof domain != "undefined") cookieVal += "; domain=" + domain; document.cookie = cookieVal;
}
//retrieves a cookie
function getCookie(name) {
  var nameEQ = name + "="; var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); }
  return null;
}

You could alter this to use whatever you’ve named your cookie functions.

Anyway, so now you have randCookieExample which has randCookieExample.val which is a number between 1 and 10.

Then you just have something like:

if (randCookieExample.val > 9) ...(and then your code runs)

Later, if you want to ratchet up the traffic, you just lower the threshold. This means that users who had a 10 are still seeing your test and users with a lower number (now above the threshold) are seeing it consistently, too.

You can use your firebug console to execute the line

randCookieExample.saveVal(10)

to give yourself a 10, which lets you turn the treatment on for yourself. Alternatively, you could add these lines to your page:

if (window.location.href.indexOf("exampleOn=true") > 0)
	randCookieExample.saveVal(11);
if (window.location.href.indexOf("exampleOn=false") > 0)
	randCookieExample.saveVal(1);

and then you could hit the page and add ?exampleOn=true and get the same result. This is beneficial if you want to let others (like QA) turn things on and off without them having to use the console.

I typically use this technique with lazy loading of javascript, so that if the user meets my criteria, I then load all the rest of my javascript, otherwise the user only gets this class and maybe a few more lines of code and then is sent on their way.

Leave a Reply

You must be logged in to post a comment.