-
Notifications
You must be signed in to change notification settings - Fork 2
Home
- 4 space indentation.
- Spaces, not literal tabs.
- No trailing whitespace.
- Every file should end with a newline.
// Use this style for inline comments. Notice the space character after "//".
// This style works fine for multi-line comments.
/**
* Use this alternate style for documenting methods and classes. This comment
* style should only appear directly above method/class definitions.
*/
Use the variable that
to maintain a reference to this when necessary.
var that = this;
Use this style:
function() {
if (a < 0) {
console.log("a is negative");
handleNegativeA();
} else if (a > 0) {
console.log("a is positive");
handlePositiveA();
} else {
console.log("a is zero or NaN");
handleOtherA();
}
}
Braces are never optional, even around single-statement blocks.
// Good:
if (!alreadyDone) {
doSomething();
}
// Bad:
if (!alreadyDone)
doSomething();
An alternate, condensed style is allowed only when calling the done
or next
callback with an error:
if (err) { done(err); return; }
// or
if (err) { next(err); return; }
If the code deviates even slightly from the above, then condensing the code into a single line is not allowed.
We're less strict than others when it comes to declaring variables. For example, it's not important that variables be declared at the top of the function. However, it's important to keep a couple rules in mind:
A variable should only be declared once per function.
// Good:
var count;
if (user) {
count = user.count;
} else {
count = 0;
}
// Bad:
if (user) {
var count = user.count;
} else {
var count = 0;
}
Never use JavaScript's condensed syntax for declaring multiple variables.
// Good:
var foo;
var bar;
// Bad:
var foo, bar;
-
a = b + 1
, nota=b+1
-
function(a, b, c) {
, notfunction(a,b,c) {
-
if (a)
, notif(a)
Note This is admittedly inconsistent, but we happen to use a denser notation for object literals than most others:
-
{a: 1, b: 2}
, not{ a: 1, b: 2 }
If the function has more than a few arguments and it's part of the class's public interface, than assert that the arguments are of the expected type. This boilerplate can be tedious, but we've found that it pays dividends in the long run. (If we ever switch to TypeScript, we can do away with it.)
function doSomething(userId, tableId, rowId, count, done) {
hs.assert(hs.utils.isValidUserId(userId));
hs.assert(hs.utils.isValidTableId(tableId));
hs.assert(hs.utils.isValidRowId(rowId));
hs.assert(hs.utils.isNonNegativeInt(count));
hs.assert(_.isFunction(done));
// stuff...
}
If the function has more than ~4 or 5 arguments, then including them as named properties of the opts
argument is recommended:
function doSomething(userId, opts, done) {
if (arguments.length === 2) {
done = opts;
opts = {};
}
hs.assert(hs.utils.isValidUserId(userId));
hs.assert(_.isFunction(done));
opts = hyperUtils.setAndEnforceDefaultOpts({
tableId: null
rowId: null,
count: 0
}, opts);
hs.assert(hs.utils.isValidTableId(opts.tableId));
hs.assert(hs.utils.isValidRowId(opts.rowId));
hs.assert(hs.utils.isNonNegativeInt(opts.count));
// stuff...
}
- Use the async lib for async control flow.
hs.async
is Airtable's wrapper around that library. We avoid other control flow options, e.g. promises, for consistency's sake. - An async function's final callback arg should be named
done
, and should always be the last argument in the function. - Inner callback functions should be named
next
(followed byinnerNext
if absolute necessary)
function getUser(userId, done) {
hs.async.waterfall([
function(next) {
doSomething(next);
},
function(next) {
doSomethingElse(next);
}
], done);
}
- Use the
Class.mod
module to facilitate creation of classes, as well as inheritance. It is a slightly modified version of John Resig's code: http://ejohn.org/blog/simple-javascript-inheritance/ - Class names should be capitalized, and instance names should not be.
- Private or protected variables and methods in a class should be prefixed with "_".
- To create singletons, use the normal class pattern, and then instantiate the object at the end of the file.
var Foo = Class.extend({
foo: function() {
// public method
},
_bar: function() {
// private method
}
});
// Export the class
module.exports = Foo;
// OR export the singleton
module.exoprts = new Foo();
- Never throw errors synchronously.
- On the server side, use
hs.utils.spawnError
to generate errors, not the nativeError
constructor. - Every async error must be handled; no error can be ignored.
- Always use
===
and!==
; never use==
or!=
.
Underscore is really handy, and we use it for almost all array/object manipulation. In particular, it should be used for all iteration.
// Good:
_.each(usersById, function(user, userId) {
doSomething(user);
});
// Bad:
var userId;
var user;
for (userId in usersById) {
if (usersById.hasOwnProperty(userId) {
user = usersById[userId];
doSomething(user);
}
}
In certain performance-critical code paths, we've begun to phase out Underscore in favor of lodah. It's a bit weird to use both libraries, so at some point we should probably switch to lodash completely.
- Use camelCase for all identifiers, e.g. function and variable names.
- All git branch names should also be camelCase.
Optimize for readability over terseness in all cases. Long and descriptive variable/method names are strongly preferred!
Don't use ||
or &&
for control flow:
// Good:
if (!alreadyDone) {
doSomething();
}
// Bad:
alreadyDone || doSomething();
// It's OK to use `||` for assigning default values though:
var count = user.count || 0;
Separate tail cals into two lines so it's easier to step through with the debugger:
// Good:
function foo() {
var ret = bar();
return ret;
}
// Bad:
function foo() {
return bar();
}