tower-style-guide v0.0.1
Tower Style Guide
General Documentation Semantics
Write in a conversational style.
- Use pronouns: I, we, you, they.
- Use colloquial expressions: a sure thing, turn-on, rip-off, OK.
- Use contractions: they're, you're, it's, here's, we've, I'm.
- Use simple words.
- If you must choose between writing naturally and being grammatically correct, write naturally.
// yay I'm going home. It's simple. // nay I am going home. It is simple.
JavaScript
Define
var
one at a time (don't use leading/trailing commas):// yay var event = require('event'); var dom = require('dom'); var assert = require('assert'); // nay var event = require('event'), dom = require('dom'), assert = require('assert'); // nay var event = require('event') , dom = require('dom') , assert = require('assert');
While the later two are minimally more optimized, minifiers like uglifyjs will make these optimizations for you. So write what is most human readable.
Use trailing commas for multi-line arrays.
// yay var events = [ 'click', 'keypress', 'focusin', 'focusout' ]; // nay var events = [ 'click' , 'keypress' , 'focusin' , 'focusout' ];
Use trailing commas for multi-line objects.
// yay var styles = { color: '#000', background: '#fff', width: 100, height: 200 }; // nay var styles = { color: '#000' , background: '#fff' , width: 100 , height: 200 };
Always use
"
double quotes when declaring JSON keys and values.// yay { "myKey": "string", "myArray": ["some stuff", "more stuff"] } // nay { myKey: 'string', 'myArray': ['some stuff', 'more stuff'] }
For strings that are not defined in JSON, default to declaring strings with
'
single quotes. In the case where your string contains special format characters or'
single quotes, use"
double quotes.// yay var str = '"Marty" is at the party!'; var specialStr = "im'oto"; // nay var str = "\"Marty\" is at the party!"; var specialStr = 'im\'oto';
For assigned functions, have no whitespace between parentheses and brackets:
){
vs.) {
.// yay exports.init = function(){ this.x; }; // nay exports.init = function() { this.x; };
For callback functions, do the same thing.
// yay route('/users') .on('exec', function(){ }); // nay route('/users') .on('exec', function() { });
For non-assigned functions, do it the other way around.
// yay function init() { this.x; }; // nay function init(){ this.x; };
This distinguishes the function declarations and function expressions.
- Indent DSL methods if they are in a new object scope.
// yay adapter('facebook') .model('user') .attr('username') .action('create') .action('find') .param('page', 'integer') .model('like'); // nay adapter('facebook') .model('user').attr('username').action('create') .action('find') .param('page', 'integer') .model('like');
Keep 1 space between native methods and parentheses (
if
,while
,for
, etc.).// yay if (x) y(); // nay if(x) y();
Emit event names in the present tense as
verb [object|property]
.// yay this.emit('define', user); this.emit('define user', user); // nay this.emit('defined user', user); this.emit('user defined', user); this.emit('user define', user);
- Emit namespaced events from most generic to most specific. This way, you can mixin more generic stuff first, and use those generic methods on specific objects.
// yay this.emit('define', user); this.emit('define facebook', user); this.emit('define facebook.user', user); // nay this.emit('define facebook.user', user); this.emit('define facebook', user); this.emit('define', user);
Pass the
this
ascontext
for the first parameter in DSL methods, instead of usingthis
as a reference. The context is stated more clearly.// yay route('/users') .on('request', function(context, next){ context.render(); }); // nay route('/users') .on('request', function(next){ this.render(); });
Place the compared value on the left instead of the right. This is unnatural at first, but it makes the code much easier to read for a newcomer.
// yay if ('string' === typeof(x)) exec(); // nay if (typeof(x) === 'string') exec();
The reason for this is, the compared-to value (e.g.
'string'
) is first, so it readsif ('string') exec()
.Leave 1 empty line at the *top of each file.
\n /** * Blank line above. */
/** * No blank line above */
- Leave 0 empty lines at the bottom of each file.
Leave 1 blank line between comments and code.
/** * GOOD */ exports.init = function(){ };
/** * BAD */ exports.init = function(){ };
For loops should be as efficient and clean as possible.
// yay for (var i = 0, n = arr.length; i < n; i++) {} // nay for (var i = 0; i < arr.length; i++) {}
Single letter variables should only be used within loops (basically for loops).
// yay for (var i = 0, n = arr.length; i < n; i++) {} // nay for (var index = 0, size = arr.length; index < size; index++) {}
For each loops (for loops but with objects) should have safe guards, which is a general good JavaScript practice.
// yay for (var key in obj) { if (obj.hasOwnProperty(key)) { delete obj[key]; } } // nay for (var key in obj) { delete obj[key]; }
Use
obj.init()
instead ofnew Obj
, whereobj.create()
should do some db/service call.// yay var newObj = obj.init(); // nay var newObj = new Obj();
For single-line arrays and objects, put one space before/after containing brackets.
// yay [ 'i386', 'x86_64' ] { status: 'active' } // nay ['i386', 'x86_64'] {status: 'active'}
Avoid aligning signs such as
=
,:
, etc. The reason is, while it does create some symmetry, it makes the code a little harder to read.// yay var x = 1; var foo = 'bar'; var hello = 'world'; // nay var x = 1; var foo = 'bar'; var hello = 'world';
If a ternary statement is too long, put it on multiple lines with
?
and:
at the start of the line.// yay exports.query = function(name){ return null == name ? query().start(this.className) : query(name); } // nay exports.query = function(name){ return null == name ? query().start(this.className) : query(name); }
If you are building a multiline string, use
+
at the beginning of the line.// yay var string = 'some ' + 'long ' + 'string '; // nay var string = 'some ' + 'long ' + 'string '; // nay var string = 'some \ long \ string ';
In EcmaScript 6, you'll be able to use backticks for multi-line strings.
Repos
Name your projects using lowercase with hyphens.
// yay var myProject = require('my-project'); // nay var myProject = require('myProject'); var myProject = require('MyProject');
Events
These are all of the events used in Tower. When creating custom APIs, see if these events can be used before defining another. Maybe we can even cut it down.
emit('define');
emit('init');
emit('exec');
emit('open');
emit('close');
emit('connect');
emit('disconnect');
emit('render');
emit('request');
emit('error');
emit('data');
Maybe route.on('request')
becomes route.on('exec')
. And route.on('connect')
becomes route.on('open')
.
Tests
Use easy to scan/understand syntax for assertions.
// yay assert(true === val); assert(false === val); assert('foo' === val); assert(undefined === val); // nay assert.isTrue(val); assert.isFalse(val); assert.equal('foo', val); assert.isUndefined(val); // - should syntax val.should.be(undefined);
Comments
Here is the general structure of a good comment:
/** * Iterate each value and invoke `fn(val, i)`. * * users.each(function(val, i){ * * }); * * @param {Function} fn * @return {Object} self * @api public */ proto.forEach = function(fn){ // ... return this; };
Readme Structure
The basic format:
- Title
- Installation
- Examples (optional)
- API
- Running Tests
- Contributing
- Notes (optional)
- License
Examples
- https://github.com/component/struct/blob/master/index.js
- https://github.com/component/pipe/blob/master/index.js
- https://github.com/component/raf/blob/master/index.js
- https://github.com/component/to-function/blob/master/index.js
- https://github.com/component/enumerable/blob/master/index.js
- https://github.com/component/network
- https://github.com/component/trace/blob/master/index.js
- http://stackoverflow.com/questions/5495984/coding-style-guide-for-node-js-apps
12 years ago