Coding Style Guide

Please see Contributing to Hoodie for more guidelines on contributing to Hoodie.

Hoodie uses the Standard JavaScript coding style.

This file explains coding-style considerations that are beyond the syntax check of Standard.

There are three sections:

  • General: coding styles that are applicable to all JavaScript code.
  • Client: coding styles that are only applicable to in-browser code.
  • Server: coding styles that are only applicable in server code.

Note: Client and Server coding styles can be contradicting, make sure to read these carefully.

General

File Structure

A typical JavaScript file looks like this (without the comments). Sort all modules that you require alphabetically within their blocks.

// If your module exports something, put it on top
module.exports = myMethod

// require Node.js core modules in the 1st block (separaeted by empty line).
// These are modules that come with Node.js and are not listed in package.json.
// See https://nodejs.org/api/ for a list of Node.js core modules
var EventEmitter = require('events').EventEmitter
var util = require('util')

// In the 2nd block, require all modules listed in package.json
var async = require('async')
var lodash = require('lodash')

// in the 3rd block, require all modules using relative paths
var helpers = require('./utils/helpers')
var otherMethod = require('./other-method')

function myMethod () {
  // code here
}

Avoid “this” and object-oriented coding styles.

Do this

function MyApi (options) {
  var state = {
    foo: options.foo
  }
  return {
    doSomething: doSomething.bind(null, state)
  }
}

function doSomething (state) {
  return state.foo ? 'foo!' : 'bar'
}

Instead of

function MyApi (options) {
  this.foo = options.foo
}

MyApi.prototype.doSomething = function () {
  return this.foo ? 'foo!' : 'bar'
}

The bind method allows for partially applied functions, that way we can pass internal state between different methods without exposing in the public API. At the same time we can easily test the different methods in isolation by setting the internal state to what ever context we want to test with.

Folder Structure

In the root, have

  • package.json
  • .gitignore (should at least list node_modules)
  • README.md
  • LICENSE (Apache License Version 2.0)

In most cases you will have index.js file which is listed in package.json as the "main" property.

If you want to split up logic into separate files, move them into a server/ folder. Put reusable, state-less helper methods into server/utils/

For tests, create a test/ folder. If your module becomes a bit more complex, split up the tests in test/unit and test/integration/. All files that contain tests should end with -test.js.

Misc

Client

Testing

Client code should be tested using tape. The reason we use tape is its support for browserify.

Libraries with sub-modules that can be required individually, like lodash

For client-side JavaScript code, it is important to limit the amount of code that is downloaded to the client to the code that is actually needed. The loadash library is a collection of utilities that are useful individually and in combination.

For example, if you want to use the merge function of lodash, require it like this:

var merge = require('lodash/merge')

If you want to use more than one function within one module, or if you want to combine multiple functions for a single operation, require the full lodash module:

var _ = require('lodash')

If multiple modules use the same lodash function, our frontend bundling tool will do the right thing and only include that code once.

Server

Testing

Server code should be tested using tap.

Libraries with sub-modules that can be required individually, like lodash

For server-side code, it is important to load the minimal amount of code into memory.

On the server require the full library, e.g.

var _ = require('lodash')

var c = _.merge(a, b)

That way, all of our server code will only ever load a single instance of lodash into memory.