-
Notifications
You must be signed in to change notification settings - Fork 33
Coding practices guide
Jérémie Astori edited this page Feb 13, 2015
·
13 revisions
- Asynchronous computations
- Immutable data structures
- Side effects
- Functional traversal vs. imperative traversal
eval
is Evil- Tests
- Prefer Promises over callbacks whenever possible. Promises are the future (see what I did?).
- Promises can be confusing. Read about it:
- The Promise object on MDN
- Promises by Forbes Lindesay
- Callbacks are imperative, promises are functional, by James Coglan
- You're Missing the Point of Promises, by Domenic Denicola
- When dealing with Node-style callbacks, use
Promise.denodeify
.
// The new readFile returns a promise rather than expecting a callback
var readFile = Promise.denodeify(require('fs').readFile);
- Use collections from Immutable.js (documentation is here).
- Prefer
Immutable.List
,Immutable.Stack
,Immutable.Set
, ... over mutableArray
. - Prefer
Immutable.Map
over mutableObject
.
- Side-effects can be a cause of errors that are hard to track down.
- Write pure functions, functions without side-effects.
- Try to respect the following convention: if a function has side effects, it does not return anything.
- Mutating an object is a side effect. Return a modified copy of an element rather than mutating the element itself.
// Good
function addElement(list, element) {
return list.push(element); // Leaves list unchanged
}
// Bad
function addElement(array, element) {
array.push(element); // Mutates array
return array;
}
- When traversing collections, make your code describe the "What" (you want to do) rather than the "How" (you want to do it). This leads to more meaningful code, focused on the actual behavior you wanted to achieve rather than the mechanics of traversing your collections. Mechanics are now abstracted. Code is also usually shorter and defines less temporary variables.
- As a rule of thumbs, this means less to no uses of
for
andwhile
loop, and more uses ofmap
,reduce
andfilter
functions. - This usually helps to separate concerns.
function double(x) { return 2 * x; }
// Good
[1, 2, 3, 4].map(double);
// Bad
function doubleArray(input) {
var result = [];
for (var i = 0; i < input.length; ++i) {
result[i] = double(input[i]); // Only this line matters in the end...
}
return result;
}
imperativeDouble([1, 2, 3, 4]);
function isEven(x) { return x % 2 === 0; }
// Good
[1, 2, 3, 4].filter(isEven);
// Bad
function evenArray(input) {
var result = [];
for (var i in input) {
if (isEven(i)) result.push(i); // Again, only this line is relevant
}
return result;
}
evenArray([1, 2, 3, 4]);
- Do not use
eval
. -
eval
has aliases:- Do not use the
Function
constructor. - Do not pass strings to
setTimeout
orsetInterval
.
- Do not use the
- Always provide tests.
- Try to make your tests self-contained. Not doing so can result in unexpected behavior when running tests locally compared to when they are run on the CI instance.