tower-style-guide

## General Documentation Semantics

npm install tower-style-guide
2 downloads in the last week
4 downloads in the last month

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 as context for the first parameter in DSL methods, instead of using this 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 reads if ('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 of new Obj, where obj.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
# Title

Quick description (1-2 sentences).

## Installation

node.js:

```
npm install tower-project
```

browser:

```
component install tower/project
```

## Example

```js
var project = require('tower-project');

// ...
```

## API

Optional brief intro.

### .on(event, fn, [capture])

Short description of some method:

```js
dom('a.remove').on('click', function(e){

});
```

### .on(event, selector, fn, [capture])

Bind delegate `event` handler function for `selector`:

```js
dom('ul li').on('click', 'a.remove', function(e){

});
```

## Running Tests

Install testem:

```bash
$ npm install -g testem
```

Run tests:

```bash
$ testem
```

Then, open all the browsers you want to test by going to the outputted url defaulted to [http://localhost:7357](http://localhost:7357)

Tests will run on any open browser linked to the stated url and your current node environment.

## Contributing

Before you send a pull request, make sure your code meets the style guidelines at [https://github.com/tower/style-guide](https://github.com/tower/style-guide) and all tests pass.

## Notes

This section is optional, but where you'd write whatever, 
like design decisions, when to use, overview, etc. 
Here you could go into the theory too (distributed data, etc.).

## Licence

MIT

Examples

npm loves you