Flight formation

The number one rule is consistency... cause nobody want to use a broken API like PHP... It's very clear and does not need further explanation.

Ok, so let's keep it consistent, but what order should we use anyway?

When designing a Javascript API, an important point one may consider is the binding possibility (i.e. using .bind() on the API methods).

Ask yourself what is the most constant parameter and what is the most variable parameter for a method.

Let's use a real-world example here.

I'm currently working on a new general purpose data validation lib (doormen). The main feature of the lib is a function that takes a schema and a data as arguments, and throws if the data does not validate according to the schema.

As of doormen v0.2.x, the syntax is now doormen( schema , data ):

// do not throw
doormen( { type: 'number' } , 1 ) ;

// throw: 'hello' is not a number
doormen( { type: 'number' } , 'hello' ) ;

But before v0.2.x, the syntax was doormen( data , schema ). What a terrible design mistake I made back then!

As you can imagine, a single schema aims to validate multiple data, hence there will be a greater number of unique data than unique schema. The schema parameter is less variable than the data parameter.

Therefore, as of v0.2.x, one is able to create a specific validator easily using .bind(), e.g.:

var singleDigitNumberValidator = doormen.bind( null , { type: 'integer', min: 0, max: 9 } ) ;

singleDigitNumberValidator( 3 ) ; // OK
singleDigitNumberValidator( 13 ) ; // Not OK
singleDigitNumberValidator( 'bob' ) ; // Not OK
...

After binding, only one argument remains!

Before v0.2.x, slightly more code was needed, and one more function call to achieve the same:

var singleDigitNumberValidator = function( data , schema ) {
    return doormen( data , { type: 'integer', min: 0, max: 9 } ) ;
} ;

singleDigitNumberValidator( 3 ) ; // OK
singleDigitNumberValidator( 13 ) ; // Not OK
singleDigitNumberValidator( 'bob' ) ; // Not OK
...

I think this rule can apply to language that do not have .bind() too, since it follows a “generic to specific” pattern.