It's important to write code that is consistent and thus maintainable. Follow these rules.
(formatting and some rules based on https://github.com/aheckmann/js-styleguide)
Here are some tools I recommend for making your development at Karma better. We use Atom Editor as our main editor and highly recommend it. Here are some helpful plugins:
- Atom-Beautify - Great way to clean up code that has gotten ugly from people editing with different editors and copypasta!
- Gist-It - Easy way to share code snippets in Slack. Make sure you set it up to use private gists!
- Linter - In-line Linting (see next two entries)
- Linter-jshint - JSHint support for linter
- Linter-json - JSON Lint support for linter
- TODO Show - Keep track of all the @TODO and @HACK code spots
- Settings:
TODOs, /TODO:?(.+$)/g, HACK, /HACK:?(.+$)/g
- Settings:
- Autocomplete Plus - Want your autocomplete to pop up automatically?
- Tabs vs Spaces
- Line Length
- Whitespace
- Braces
- Parenthesis
- Variable and Property Names
- Constructor Names
- Function Spacing
- Semi-colons
- Variables
- Self
- Errors
- Return Early
- Inline Documentation
- Modifying Native Prototypes
- CoffeeScript
- Use Strict
- JSHint
- Single/Double Quotes
Spaces, always. 4 spaces because our monitors are huge.
120 characters max. We have giant monitors.
No trailing whitespace allowed. Clean up after yourself.
Place opening braces on the same line as the statement.
if (areWeWritingJava)
{
// hmmmm
}
if (nicelyDone) {
// ok!
}
Leave space before and after the parenthesis for if/while/for/catch/switch/do
// inconsistent
if(weAreHavingFun){
console.log('Wheeee!');
}
// consistent
if (weAreHavingFun) {
console.log('Wheeee!');
}
Use lower camel case and be descriptive. Aim for one word descriptions if possible.
// inconsistent
var plan_query = model.findById(plan_id);
// consistent
var planQuery = model.findById(planId);
Constructors should use upper camel case to hint to its intended use.
function Movie(id, title) {
if (!(this instanceof Movie)) {
return new Movie(id, title);
}
this.id = id;
this.title = title;
};
var gravity = new Movie(1, 'Gravity');
When executing a function, leave no space between it's name and parens.
eatIceCream (); // inconsistent
eatIceCream(); // consistent
Leave a space between your function
declaration/expression parenthesis and the opening {
.
function eatIceCream(){
// inconsistent
};
function eatIceCream() {
// consistent
};
There should be no empty lines between the function name and the first line of code.
// inconsistant
function eatIceCream() {
var dessert = bowl().of(iceCream);
human.eat(desert);
}
// consistant
function eatIceCream() {
var dessert = bowl().of(iceCream);
human.eat(desert);
}
Use em.
var semis = function() {
// codez
}
['property'].forEach(console.log) // TypeError: Cannot call method 'forEach' of undefined
var semis = function() {
// codez
}; // <--------
['property'].forEach(console.log); // property 0 [ 'property' ]
It's really great if you take the extra time to learn where they're actually necessary, you may just be surprised how few places there are. I personally think it's easier to learn the rules and use them only where they're required, but for even mid-size teams, it's simpler to just use 'em and move on.
When declaring multiple variables, use "var first" style.
var fix = true;
var nice = 'you best';
var woot = require('woot');
This makes for easier copy/paste later on and less futzing around with semi-colons and commas.
Name variable references to this
"self".
Dancer.prototyp.selfie = function selfie() {
var self = this;
return function() {
console.log(self);
};
};
If you must throw an error, make sure what you throw is an instance of Error
.
For example:
if (!exists) {
throw 'invalid!'; // not very helpful
}
if (!exists) {
throw new Error('invalid!'); // more helpful
}
Each instance of Error
has a stack
property which aids in debugging.
try {
throw new Error('hmmmm');
} catch (err) {
console.error(err.stack);
}
Can I throw:
strings
? nopenumbers
? noarrays
? naddaobjects
that have a message property? forget itup
? please not on me
Same goes for callbacks. If an error condition is identified, pass an instance of Error
to the callback.
app.use(function(req, res, next) {
var err = failedValidation(req)
? new Error('could not parse request')
: undefined;
next(err);
});
Return early whereever you can to reduce nesting and complexity.
function checkSomething(req, res, next) {
if (req.params.id) {
if (isValidId(req.params.id)) {
find(req.params.id, function(err, doc) {
if (err) return next(err);
res.render('plan', doc);
});
} else {
next(new Error('bad id'));
}
} else {
next();
}
};
// return early
function checkSomething(req, res, next) {
if (!req.params.id) {
return next();
}
if (!isValidId(req.params.id)) {
return next(new Error('bad id'));
}
find(req.params.id, function(err, doc) {
if (err) return next(err);
res.render('plan', doc);
});
};
Each function should have corresponding JSDoc-style comments that include parameters and return values. Examples are always appreciated.
/**
* Adds two numbers.
*
* Example
*
* var result = add(39, 12);
*
* @param {Number} num1
* @param {Number} num2
* @return {Number}
*/
function add(num1, num2) {
return num1 + num2;
};
Don't do it. It causes debugging headaches, breaks expected behavior and introduces potential incompatibility with new versions of V8. There's always a better way.
// please no
Array.prototype.contains = function(needle) {
return this.indexOf(needle) > -1;
};
// For example, create a helper module with a function that accepts an array:
// helpers/array.js
exports.contains = function(array, needle) {
return array.indexOf(needle) > -1;
};
Is banned. Just learn JavaScript. Really. Its a simple language.
Always. No exceptions. At the top of every file
'use strict';
All files must pass jshint validation, and it's built into our gruntfile to aid with this.
If you love yourself, you'll install something in your editor to help with this inline.
Rules:
{
"node": true,
"browser": true,
"jquery": true,
"eqeqeq": true,
"indent": 4,
"latedef": true,
"quotmark": "single",
"trailing": true,
"undef": true,
"unused": true,
"curly": true,
"camelcase": true,
"strict": true
}
We always use single quotes in JS files because that's what I decided. There doesn't seem to be a winner
(http://stackoverflow.com/questions/242813/when-to-use-double-or-single-quotes-in-javascript)
However, JSON files require double-quotes to be validated, so pure JSON files use double.