As of ECMAScript 1.8.5 javascript implemented the bind() function which can
also be found in underscore.js as _.bind(). It allows you to bind a
function to a this context as well as bind some predefined arguments.
Binding predefined arguments in other functional languages like haskell is
known as partial function application and goes by the name of currying.
So whats wrong with bind
The problem with bind is that it has two majorly different use cases, context
binding and partial function application. This makes reading code that
contains bind() calls in it slightly less concise because just reading the
name of the function isn’t enought to tell you what the intended goal of the
operation is. It can be used for context binding, partial function application
or both.
Sounds like a swiss army knife
Swiss army knife functions are something to be weary of when you intend to
write concise and readable code. By looking at the funciton protocol for
bind it seems like it was originally intended to be used just for context
bind and partial function application was almost an afterthought. For this
reason, when you use the bind function strictly for context binding not
only does it create intuitive code but also cleaner looking code. You’ll see
what i mean when you try to use the bind function strictly for currying as
it creates the opposite effect.
So the undefined parameter in the previous example is a staple wtf code
sighting in javascript. We can prevent having to pass undefined while
making our code more concise by using a custom implementation of curry. You
can see how the method we composed becomes more concise in the following
example.
123456789101112131415161718192021
/**
* Custom curry implementation. There are probably cleaner ways to
* implement `curry()` but this is just the one i use and it works
Javascript is a programming language that has most of the killer functional
programming features you can possibly bake into a C syntax styled language with
a hint of prototypical inheritance from the self programming language. This
presents you with an interesting multi-paradigm programming environment that
through better or worse practices can let you choose which style to program in.
When i write javascript my inner geek gets all giddy because it’s always the
perfect excuse for me to exercise functional programming practices in a
widely accepted mainstream language. I love functional programming so much
in javascript that the library i get the most mileage out of by a landslide is
underscore.js, a functional programming library for javascript. Even if you
exclude the fact that i use underscore.js in both client side javascript and
server side in node.js, it still remains the library that i use the most
independently in each environment.
Patterns and abstraction
In functional programming whenever you find yourself typing a similar code
pattern multiple times you should consider abstracting it. This is actually
true with most programming languages but something of a religious practice
in functional programming. However, functional programming languages like
javascript have the advantage of having high order functions and lexical
closures allowing you to abstract certain patterns better and more concisely
then is possible in non functional languages.
Error handling in node.js
As an awesomely consistent and well implemented set of APIs, all API calls in
node.js that perform any kind of IO take a function callback to run on IO
completion. This is a very fundamental practice at the core of the node.js
asynchronous evented model. A familiar site to anyone familiar with node is the
pattern of arguments that are passed to the callback. Typically, asynchronous
callbacks will take one or two arguments, (error) and (error, value) . The
most important part for this article being that error is always the first
argument passed to the callback.
The error passed as the first argument to any aysnchronous callback is
representative of any errors that might have occurred during the asynchronous
operation. Error will be false if no error was raised and non false otherwise.
In node.js you often have nested aysnchronous requests and a common approach
to error handling is to pass the errors back up the event chain to be handled
by a layer knowing what to do with it. This is demonstrated in the bellow
pseudo code js example.
12345678910111213141516171819202122232425
varexpress=require("express"),
redis=require("redis").createClient(),
app=express.createServer();
functongetLatestNews(next){
redis.lrange("news",0,25,function(error,value){
if(error){
next("failed fetching news");
}else{
next(false,value);
}
});
}
app.get("/",function(req,res){
getLatestNews(function(error,news){
if(error){
globalErrorHandler(error);
}else{
res.send(news);
}
});
});
app.listen(80);
There it is the error passing pattern. If you write node.js code you can
probably find this pattern throughout your code base. If you can’t it means
you’re probably not handling errors which is a big no go.
The pattern can be written a couple different ways
1234567891011121314151617181920212223
/**
* strictly nested approach
*/
if(error){
// pass failure
next(error);
}else{
// pass success
next(false);
}
/**
* refactored to avoid deeply nested code
*/
if(error){
// pass failure and return
next(error);
return;
}
// do work
// pass success
next(false);
So the money making question is how do we factor out this repetitive pattern
being the ace functional programmers that we like to think that we are?
Heres the solution i came up with, i call it the pass pattern. I call it the
pass pattern, but really it’s more of an abstraction.
123456789101112131415161718192021222324252627
varexpress=require("express"),
redis=require("redis").createClient(),
app=express.createServer();
functionpass(next,after){
returnfunction(error,value){
if(error){
after(error,value);
}else{
next(value);
}
};
}
functongetLatestNews(next){
redis.lrange("news",0,25,pass(function(value){
next(false,value);
},next));
}
app.get("/",function(req,res){
getLatestNews(pass(function(news){
res.send(news);
},globalErrorHandler));
});
app.listen(80);
So this requires you to setup a function called pass which acts as a closure
generator for augmenting the asynchronous callback. The error checking gets
dropped from the asynchronous callback, yet the error checking still takes
place. The asynchronous callback itself is only ran when no error is present
and as a byproduct, we can safely drop the error argument from the first
argument of the callback. Just as important, the next callback is automatically
forwarded or “passed” the error if one is present.
The above example of pass is just introductory code. The full version of the
pass abstraction i use in my code is as follows.
1234567891011121314
// Yeah i use underscore.js so much i add it as a mixin to underscore
_.mixin({
pass:function(next,after,customError,context){
returnfunction(error){
varargs=Array.prototype.slice.call(arguments,1);
if(error){
args.unshift(customError||error);
after.apply(context,args);
}else{
next.apply(context,args);
}
}
}
});
This version allows me to override error messages so if i get back a DB failure
error from the database while calling it from the registration form i can
override the message with something more meaningful to the user that will get
passed along instead. My version also allows context binding so i can avoid
some var self = this; annoyances.
Some people know them as A/B tests and i think thats really a shame. The name
A/B testing implies your intent is to use the parallel testing suite of your
choice to gather performance analytics usually on content based differences and
variances in the UI. There is a huge value add to using A/B testing just for
collecting performance analytics so i’m not claiming that it’s a misuse of
parallel test suite implementations. However, the value value adds with
parallel testing doesn’t just end with performance testing as it can be used
to enhance your product release process, your QA process and even your
development process.
Improving the release process
I’ve worked on web products where we’ve done production code releases at
midnight once a week and on ones that have one or more releases a day during
peak hours. Depending on your past experiences you may think that releasing
during peak hours that often is just asking for the fail whale to strike on
a daily basis. However, my experience with both was that the midnight releases
during hours of really light load where the most chaotic and error prone by
an order of magnitude. So coming from that background wouldn’t releasing every
day during peak hours be one of the most counter intuitive things ever?
There are no silver bullets and the best way to slay a beast is with lots of
lead bullets. I can talk about the value of hiring competent developers,
using continuous integration and various release strategies to improve the
release process. However, the lead bullet of this blog post is parallel
testing.
When you’re developing a new feature you can start it off by wrapping
both the new and old implementation in a parallel test and setting the exposure
of the old implementation to 100% with the new implementation set to 0%
with a manual override on your test user id so that your test account will be
presented with the functionality of the new implementation. This new feature
can then be committed up the chain and even to prod with the same 100% to 0%
test ratio and public facing end users will not have access to the new feature.
At this point the only people with access to the new feature would be typically
developers, Q/A and various business owners inside the company all of which
would be able to test the new functionality in a production environment.
Once the new functionality has been pushed to production, sufficiently tested
internally and vetted by all product owners. The release of the product is
simply a toggle of the percentage in the parallel test suite from 100% old 0%
new to 0% old 100% new. The concurrent test wrapper can even be left in place
for undefined amounts of time and you can roll it back and push it back out
all from a GUI/WebUI.
Improving the Q/A process
The Q/A process at the places i’ve worked at is always tightly coupled with
the release process so i’ve already inherently discussed some of the benefits
on how parallel test suites can be used to improve the Q/A process by talking
about how it can be used to improve the release process. IE: being able to test
new features in production in a manner not publicly visible to users is a
huge improvement to the Q/A process alone if you couldn’t already do that
before.
Another way parallel tests can be used to improve the Q/A process is they allow
you to do selective releases. It’s not uncommon for certain sites to have
select users who are highly active, vocal or are just in good contact with
the business. You can do selective releases where only employees and those
selected users will get initial “exclusive” test access to the feature before
it gets released with 100% exposure. This is an easy and almost free way of
crowd-sourcing a part of your Q/A department to users you can trust and have
past relationships with.
Improve the development process
It first occurred to me that parallel tests can be used to improve the
development process when i encountered an article by John Carmack about parallel
implementations. Basically whenever he wants to test an alternative
implementation of a feature, instead of refactoring the old implementation in
place or scrapping it he wraps the old and the new implementation in parallel
tests that he can toggle in real time from a console.
This is great for if you want to run benchmarks against alternate
implementations because theres a minimal impact on the rest of the code and
if the new implementation turns out to be worse you can simply throw out the
concurrent test and restore the original implementation as it was without
having to dig through branches, tags or commits in version control.
TL;DR
Parallel tests for releases
Enable/Disable features from a control panel instead of only source control
Incremental releases - bucket testing
Parallel tests for Q/A
Selective releases - crowd sourcing Q/A
Private beta tests in production before public release
Parallel test for the development environment
Enables you to develop alternative implementations and test them back and foward with a toggle