Coding style

Our code must be as clean and easy to read as possible.

That is actually an art of programming – to take a complex task and code it in a way that is both correct and human-readable.

One thing to help is the good code style.

Syntax

A cheatsheet with the rules (more details below):

Now let’s discuss the rules and reasons for them in detail.

Nothing is “carved in stone” here. Everything is optional and can be changed: these are coding rules, not religious dogmas.

Figure brackets

In most JavaScript projects figure brackets are written on the same line, not on the new line. A so-called “egyptian” style. There’s also a space before an opening bracket.

An edge case is a single-line if/for. Should we use brackets at all? If yes, then where?

Here are the annotated variants, so you can judge about their readability on your own:

As a summary:

  • For a really short code one line is acceptable: like if (cond) return null.
  • But a separate line for each statement in brackets is usually better.

Line length

The maximal line length should be limited. No one likes to eye-follow a long horizontal line. It’s better to split it.

The maximal line length is agreed on the team-level. It’s usually 80 or 120 characters.

Indents

There are two types of indents:

  • A horizontal indent: 2(4) spaces.

    A horizantal identation is made using either 2 or 4 spaces or the “Tab” symbol. Which one to choose is a kind of an old holy war. Spaces are more common nowadays.

    One of advantages of spaces over tabs is that they allow more flexible configurations of indents than the “Tab” symbol.

    For instance, we can align the arguments with the opening bracket, like this:

    show(parameters,
         aligned, // 5 spaces padding at the left
         one,
         after,
         another
      ) {
      // ...
    }
  • A vertical indent: empty lines for splitting the code in logical blocks.

    Even a single function can often be divided in logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically:

    function pow(x, n) {
      let result = 1;
      //              <--
      for (let i = 0; i < n; i++) {
        result *= x;
      }
      //              <--
      return result;
    }

    Insert an extra newline where it helps to make the code more readable. There should not be more than 9 lines of code without a vertical indentation.

A semicolon

A semicolons should be after each statement. Even if could possibly be skipped.

There are languages where a semicolon is truly optional. It’s rarely used there.

But in JavaScript there are few cases when a line break is sometimes not interpreted as a semicolon. That leaves a place for programming errors, so semicolons should be at place.

Nesting levels

There should not be too many nesting levels.

Sometimes it’s a good idea to use the “continue” directive in the loop to evade extra nesting in if(..) { ... }:

Instead of:

for (let i = 0; i < 10; i++) {
  if (cond) {
    ... // <- one more nesting level
  }
}

We can write:

for (let i = 0; i < 10; i++) {
  if (!cond) continue;
  ...  // <- no extra nesting level
}

The similar thing can be done with if/else and return.

For example, two constructs below are identical.

The first one:

function pow(x, n) {
  if (n < 0) {
    alert("Negative 'n' not supported");
  } else {
    let result = 1;

    for (let i = 0; i < n; i++) {
      result *= x;
    }

    return result;
  }
}

And this:

function pow(x, n) {
  if (n < 0) {
    alert("Negative 'n' not supported");
    return;
  }

  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

…But the second one is more readable, because the “edge case” of n < 0 is handled early on, and then we have the “main” code flow, without an additional nesting.

Functions below the code

If you are writing several “helper” functions and the code to use them, then there are three ways to place them.

  1. Functions above the code that uses them:

    // function declarations
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
    
    // the code which uses them
    let elem = createElement();
    setHandler(elem);
    walkAround();
  2. Code first, then functions

    // the code which uses the functions
    let elem = createElement();
    setHandler(elem);
    walkAround();
    
    // --- helper functions ---
    
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
  3. Mixed, a function is described where it’s first used.

Most of time, the second variant is preferred.

That’s because when reading a code, we first want to know “what it does”. If the code goes first, then it provides that information. And then maybe we won’t need to read functions at all, especially if their names are adequate to what they’re doing.

Style guides

There are many details in the code style.

As the team becomes bigger, a common agreement on them becomes the “team style guide”.

There are many open style guides, for instance:

There exist more there in the wild.

You can browse them and choose something as a base. As you become more mature in JavaScript programming, you might want to read them all to pick up the common principles.

Style checkers

There are tools that can check the code style automatically. They are called “linters”.

The great thing about them is that style-checking also finds some bugs, like a typo in variable name or a function.

So it’s recommended to install one, even if you don’t want to stick to a “code style”. They help to find typos – and that’s already good enough.

Most well-known tools are:

  • JSLint – one of the oldest open-source solutions.
  • JSHint – the more “featured” variant of JSLint.
  • ESLint – the newest breed.

All of them can do the job. The author uses ESLint.

Here are simple steps to start using it:

  1. Install Node.JS.
  2. Install eslint: npm i -g eslint (npm is Node.JS package installer).
  3. Create a config file .eslintrc in your JavaScript project (the dot at the start is mandatory).

An example of .eslintrc:

{
  "extends": "eslint:recommended",
  "env": {
    "browser": true,
    "es6": true
  },
  "rules": {
    "no-console": 0,
    "no-constant-condition": ["error", { "checkLoops": false }]
  },
  "indent": 2
}

Then install/enable the plugin for your editor that integrates with ESLint. The majority of editors have it.

Also you can see the manual for advanced examples, rules and options of ESLint.

Summary

All syntax rules from this chapter and the style guides aim to increase readability.

All of them are debatable.

When we think about “how to write better?”, the sole criterion is “what makes the code more readable and easier to understand? what helps to evade errors?”

Tasks

importance: 4

What’s wrong with the code style below?

function pow(x,n)
{
  let result=1;
  for(let i=0;i<n;i++) {result*=x;}
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'')
if (n<=0)
{
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else
{
  alert(pow(x,n))
}

Fix it.

You could note the following:

function pow(x,n)  // <- no space between arguments
{  // <- figure bracket on a separate line
  let result=1;   // <- no spaces to the both sides of =
  for(let i=0;i<n;i++) {result*=x;}   // <- no spaces
  // the contents of { ... } should be on a new line
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'') // <-- technically possible,
// but better make it 2 lines, also there's no spaces and ;
if (n<0)  // <- no spaces inside (n < 0), and should be extra line above it
{   // <- figure bracket on a separate line
  // below - a long line, may be worth to split into 2 lines
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else // <- could write it on a single line like "} else {"
{
  alert(pow(x,n))  // no spaces and ;
}

The fixed variant:

function pow(x, n) {
  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

let x = prompt("x?", "");
let n = prompt("n?", "");

if (n < 0) {
  alert(`Power ${n} is not supported,
    please enter an integer number greater than zero`);
} else {
  alert( pow(x, n) );
}
Tutorial map

Comments

read this before commenting…
  • You're welcome to post additions, questions to the articles and answers to them.
  • To insert a few words of code, use the <code> tag, for several lines – use <pre>, for more than 10 lines – use a sandbox (plnkr, JSBin, codepen…)
  • If you can't understand something in the article – please elaborate.