Skip to content
This repository has been archived by the owner on Jun 8, 2020. It is now read-only.

Latest commit

 

History

History
454 lines (326 loc) · 8.36 KB

style-guide.md

File metadata and controls

454 lines (326 loc) · 8.36 KB

This is a guide, not a law - use your discretion. Mostly based on Felix Geisendörfer's guide with our own tweaks.

Indention

Use 2 spaces for indenting your code and swear an oath to never mix tabs and spaces - a special kind of hell is awaiting you otherwise.

Newlines

Use UNIX-style newlines (\n), and a newline character as the last character of a file. Windows-style newlines (\r\n) are forbidden inside any repository.

No trailing whitespace

Just like you brush your teeth after every meal, you clean up any trailing whitespace in your JS files before committing. Otherwise the rotten smell of careless neglect will eventually drive away contributors and/or co-workers.

Use Semicolons

According to scientific research, the usage of semicolons is a core value of our community. Consider the points of the opposition, but be a traditionalist when it comes to abusing error correction mechanisms for cheap syntactic pleasures.

Use single quotes

Use single quotes, unless you are writing JSON.

Right:

const foo = 'bar';

Wrong:

const foo = "bar";

Opening braces go on the same line

Your opening braces go on the same line as the statement, with whitespace before and after the condition, followed by a new line.

Right:

if (true) {
  console.log('winning');
}

Wrong:

if (true)
{
  console.log('losing');
}

if (true) { console.log('losing'); }

if(true){
  console.log('winning');
}

Method chaining

One method per line should be used if you want to chain methods.

You should also indent these methods so it's easier to tell they are part of the same chain.

Right:

User
  .findOne({ name: 'foo' })
  .populate('bar')
  .exec(() => true);

Wrong:

User
.findOne({ name: 'foo' })
.populate('bar')
.exec(() => true);

User.findOne({ name: 'foo' })
  .populate('bar')
  .exec(() => true);

User.findOne({ name: 'foo' }).populate('bar')
.exec(() => true);

User.findOne({ name: 'foo' }).populate('bar')
  .exec(() => true);

Use lowerCamelCase for variables, properties, and function names

Variables, properties and function names should use lowerCamelCase. They should also be descriptive. Single character variables and uncommon abbreviations should generally be avoided.

Right:

const adminUser = db.query();

Wrong:

const admin_user = db.query();

Use UpperCamelCase for class names

Class names should be capitalized using UpperCamelCase.

Right:

function BankAccount() {
}

Wrong:

function bank_Account() {
}

Use snake_case for CouchDB document property names

All property names in CouchDB documents use lowercase underscore-separated formatting.

Right:

{
  "word": "values can have spaces and CAPS",
  "multiple_words": true
}

Wrong:

{
  "UPPER_CASE_NAME": false,
  "lowercasename": false,
  "camelCaseName": false,
  "kebab-case-name": false,
  "Title_case_name": false,
  "sTuDlYcAsEnAmE": false
}

Use const and let

There is no longer a good reason to use var. Use const whenever you can, and let when you must. Hardcoded constants should be named in all UPPERCASE.

Right:

const DELAY = 10 * 1000;
const output = input * 10;
let temp = 50;
let unknown;

Wrong:

var DELAY = 10 * 1000;

Use arrow functions

Use arrow functions as much as possible for cleaner code and better scoping. Omit the return keyword when the entire function definition fits on one line. Omit the parens when taking a single parameter.

There are exceptions to this rule including when you want to access arguments or this, or when you want to be able to debug browserified code.

Right:

let result = '';

const append = a => {
  result += a;
};

const combine = (a, b) => {
  result = a + b;
};

const getResult = () => result;

Wrong:

let result = '';

const append = (a) => {
  result += a;
};

const combine = function(a, b) {
  result = a + b;
};

const getResult = () =>
  result;

Object / Array creation

Put short declarations on a single line. For long declarations put a line break after each comma.

Right:

const a = ['hello', 'world'];
const b = {
  good: 'code',
  'is generally': 'pretty',
};

Wrong:

const a = [
  'hello', 'world'
];
const b = {"good": 'code'
        , is generally: 'pretty'
        };
const c = ['one', 'two',
           'three', 'four'];

Use the === operator

Programming is not about remembering stupid rules. Use the triple equality operator as it will work just as expected.

Right:

if (a !== '') {
  console.log('winning');
}

Wrong:

if (a == '') {
  console.log('losing');
}

Do not extend built-in prototypes

Do not extend the prototype of native JavaScript objects. Your future self will be forever grateful.

Right:

const a = [];
if (!a.length) {
  console.log('winning');
}

Wrong:

Array.prototype.empty = function() {
  return !this.length;
}

const a = [];
if (a.empty()) {
  console.log('losing');
}

Use descriptive conditions

Any non-trivial conditions should be assigned to a descriptively named variable or function:

Right:

const isValidPassword = password.length >= 4 && /^(?=.*\d).{4,}$/.test(password);

if (isValidPassword) {
  console.log('winning');
}

Wrong:

if (password.length >= 4 && /^(?=.*\d).{4,}$/.test(password)) {
  console.log('losing');
}

Write small functions

Keep your functions short. A good function fits on a slide that the people in the last row of a big room can comfortably read. So don't count on them having perfect vision and limit yourself to ~15 lines of code per function.

Return early from functions

To avoid deep nesting of if-statements, always return a function's value as early as possible.

Right:

function isPercentage(val) {
  if (val < 0) {
    return false;
  }

  if (val > 100) {
    return false;
  }

  return true;
}

Wrong:

function isPercentage(val) {
  if (val >= 0) {
    if (val < 100) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}

Or for this particular example it may also be fine to shorten things even further:

function isPercentage(val) {
  var isInRange = (val >= 0 && val <= 100);
  return isInRange;
}

Adding documentation comments

To add documentation comments that will be built using jsdocs, use jsdoc block tags. For angular code use the angular tags, see examples.

Try to write comments that explain higher level mechanisms or clarify difficult segments of your code. Don't use comments to restate trivial things.

Right:

/**
 * 'ID_SOMETHING=VALUE' -> ['ID_SOMETHING=VALUE', 'SOMETHING', 'VALUE']
 * @type {boolean}
 */
const matches = item.match(/ID_([^\n]+)=([^\n]+)/));

/**
 * Loads a user. This function has a nasty side effect where a failure to increment a
 * redis counter used for statistics will cause an exception. This needs
 * to be fixed in a later iteration.
 * @param {string} id the user id
 * @param {function} cb a callback function that applied to the user
 */
function loadUser(id, cb) {
  ...
}

Wrong:

/**
 * Execute a regex
 */
const matches = item.match(/ID_([^\n]+)=([^\n]+)/);

/**
 * Usage: loadUser(5, function() { ... })
 */
function loadUser(id, cb) {
  ...
}

/**
 * Check if the session is valid
 */
const isSessionValid = (session.expires < Date.now());
/** If the session is valid */
if (isSessionValid) {
  ...
}

Object.freeze, Object.preventExtensions, Object.seal, with, eval

Crazy stuff that you will probably never need. Stay away from it.

Getters and setters

Do not use setters, they cause more problems for people who try to use your software than they can solve.

Feel free to use getters that are free from side effects, like providing a length property for a collection class.