Well written code by several authors should look like well written code by one author. To this end, everyone should write code in the same style and formatting. This serves multiple purposes, and it should be pretty clear what the benefits of consistent style with no arguments are.
This is the guide for the Entrago CMS backend codebase.
Use them with statements. Note that blocks do not get semicolons, but do-while
does after the
condition. JSHint won't give you an option for this anyway.
All functions and variables should be named in camelCase. The two exceptions are constructor functions, which should be camelCase with the initial letter also in upper case, and constants, which should be in ALL_CAPS.
A single space should separate variables from all operators. For example:
var a = 1;
var b = a * 2;
All functions, anonymous and named, get exactly one whitespace between function
and the opening
bracket for the argument list. For example:
var test = function (a, b, c) {
....
};
function test(a, b, c) {
....
}
// Maybe your function is recursive, so the following can make sense.
exports.recursive = function recursive(a, b, c) {
....
};
Note the semicolon in the first and third examples, which are expressions, whereas the second is a declaration.
Any code in controllers should be considered hot. This means that any unnecessary array methods and
underscore should be avoided for performance reasons in these. In fact, basically the only place an
Array.prototype.forEach
and family is appropriate is in startup code, since these code paths
typically run once. The exception to this rule is if a function provided by underscore of the array
prototype saves significant space and is easier to read. For the most part, a plain old for
loop
is the same size and just as readable.
Keep functions small. If the function is more than 50 lines of code (with comments) then it probably needs to be broken up.
Given that functions are small, deep nesting of branched code is unlikely. This means that often you
can simply return from if
branches and avoid else
altogether. This avoids and linearises nasty
lumps of nested code. Your functions will have the appearance of filtering out the simple cases
first.
If you have a set of nested callbacks, or find yourself counting callbacks, stop doing what you're
doing and refactor your code to use the async module. In particular, get used to the async series
,
parallel
, auto
and each
functions.
Don't use async.waterfall
. async.waterfall
makes it hard to move component functions around, and
is a common source of bugs. Instead of waterfall
, use series
with subroutine like component
functions editing data in the surrounding scope, to which all components have access. That brings
us to...
Functions return a result and may also edit data in scopes that they have access to, or any arguments that are objects. Lower level languages sometimes make the distinction between functions and pure functions. Pure functions do not have any side effects, and may only return a result. i.e. they do not alter the arguments passed in or scopes outside their own. Going way back, fortran made the distinction between functions and subroutines. Subroutines are used to modify the arguments that are passed in, and so may be considered the opposite of a pure function.
Of course, in JavaScript there are no such limitations, but it can be useful to impose them. Have
you ever seen an Array.prototype.map
with other data being edited in the callback function? That
is bad. If you want to do that, then use forEach
and push
. The map
method should only take a
pure function as a callback since that is the expectation of anyone coming from a functional
programming background.
In the case of asynchronous subroutine-like functions, these may return a scope for chaining.
Otherwise the rules apply to the arguments passed to the callback. There should only be one
(optional) error argument. This fits will with the async
methods series
, parallel
and auto
.
Try wherever possible to make your functions, synchronous and asynchronous, either pure or subroutine-like. I promise that your code will become cleaner and easier to reason about.