DEV Community

Cover image for NHA Coding Standards
Rick Hopkins for National Heritage Academies

Posted on

NHA Coding Standards

INTRODUCTION

This is the National Heritage Academies (NHA) School Applications Development team's coding standards page. Feel free to use these standards for your own reference. As the development team at NHA has grown over the past couple years so has the importance of common coding practices and standards. This article is meant to serve as the agreed upon standards to be followed by the NHA School Applications Development team. These standards are meant to help with:

  1. Keeping our code consistent
  2. Making our code easy to read and understand
  3. Making our code easier to maintain

The following sources were used to compile this list of standards.

https://medium.com/javascript-in-plain-english/19-simple-javascript-coding-standards-to-keep-your-code-clean-7422d6f9bc0

GENERAL CODING STANDARDS

Always use semicolons (;)

Even though the semicolon is optional in JavaScript, we are choosing to end all statements with the semicolon. This is a consistent requirement across JavaScript, TypeScript, C#, and even SQL.

Always use curly braces around control structures.

Braces are required for all control structures (i.e. if, else, for, do, while, etc). Do use use single line if statements. The curly brace should start on the same line as the control structure and close on a new line. There should be a space before the opening curly brace.

Fail:

if (val == 2) doSomething();
if (val == 2)
    doSomething();
if (val == 2)
    doSomething();
else
    doSomethingElse();
Enter fullscreen mode Exit fullscreen mode

Pass:

if (val === 2) {
    doSomething();
}
if (val == 2) {
    doSomething();
} else {
    doSomethingElse();
}
Enter fullscreen mode Exit fullscreen mode

Try to reduce nesting

Nesting if statements within if statements can lead to messy, unreadable code. Always look for ways to avoid nesting if at all possible. Also try to avoid else if statements.

Fail:

if (myNumber > 0) {
  if (myNumber > 100) {
       if (!hasDiscountAlready) {
           return addDiscountPercent(0);
} else {
           return addDiscountPercent(10);
       }
  } else if (myNumber > 50) {
    if (!hasDiscountAlready) {
       return addDiscountPercent(5);
    }
  } else {
    if (!hasDiscountAlready) {
      return addDiscountPercent(0);
    } else {
      return addDiscountPercent(1);
    }
}
} else {
    error();
}
Enter fullscreen mode Exit fullscreen mode

Pass:

if (myNumber <= 0) {
   return error;
}
if (!hasDiscountAlready) {
    return addDiscountPercent(0);
}
if (myNumber > 100) {
    return addDiscountPercent(10);
}
if (myNumber > 50) {
    return addDiscountPercent(5);
}
return addDiscountPercent(1);
Enter fullscreen mode Exit fullscreen mode

Switch statements should use break and have a default

Try not to use switch statements, but if you must then make sure to each break condition and use default. Like if statements, the curly braces should start on the same line as the switch statement and end on a new line. There should be a space before the opening curly brace.

Fail:

switch (myNumber) {
  case 10:
   addDiscountPercent(0);
  case 20:
   addDiscountPercent(2);
  case 30:
   addDiscountPercent(3);
}
Enter fullscreen mode Exit fullscreen mode

Pass:

switch (myNumber) {
  case 10:
    addDiscountPercent(0);
    break;
  case 20:
    addDiscountPercent(2);
    break;
  case 30:
    addDiscountPercent(3);
    break;
  default:
    addDiscountPercent(0);
    break;
}
Enter fullscreen mode Exit fullscreen mode

Only use one variable per declaration

It is a cleaner and more understandable way to declare your variables.

Fail:

const a = 2, b = 3;
Enter fullscreen mode Exit fullscreen mode

Pass:

const a = 2;
const b = 3;
Enter fullscreen mode Exit fullscreen mode

TYPESCRIPT

The following rules are based on typescript but should also be followed where applicable to JavaScript.

When comparing use === instead of ==

Using === matches on both the type and value.

Fail:

if (val == 2)
Enter fullscreen mode Exit fullscreen mode

Pass:

if (val === 2)
Enter fullscreen mode Exit fullscreen mode

Never use var.

Use const for values that cannot be reassigned and let for anything else. Favor using const as much as possible.

Fail:

var value: number = 100;
Enter fullscreen mode Exit fullscreen mode

Pass:

const value1: number = 100;
let value2: number = 200;
Enter fullscreen mode Exit fullscreen mode

Always set the type for variables and properties.

Fail:

const value = 100;

class CarModel {
    private _value = 100;
}
Enter fullscreen mode Exit fullscreen mode

Pass:

const value: number = 100;

class CarModel {
    private _value: number = 100;
}
Enter fullscreen mode Exit fullscreen mode

Always set the return type for functions and class methods.

Fail:

function callback() {
    return 'hello world';
}

class CarModel {
    callback() {
        return 'hello world';
    }
}
Enter fullscreen mode Exit fullscreen mode

Pass:

function callback(): string {
    return 'hello world';
}

class CarModel {
    callback(): string {
        return 'hello world';
    }
}
Enter fullscreen mode Exit fullscreen mode

Always set the argument types for functions and class methods.

Fail:

function callback(inputStr) {
    return inputStr;
}

class CarModel {
    callback(inputStr) {
        return inputStr;
    }
}
Enter fullscreen mode Exit fullscreen mode

Pass:

function callback(inputStr: string): string {
    return inputStr;
}

class CarModel {
    callback(inputStr: string): string {
        return inputStr;
    }
}
Enter fullscreen mode Exit fullscreen mode

Avoid the use of any as a type as much as possible

Using any can allow for too many unknowns in what type of data you are dealing with. While it can't be avoided entirely, it should be very limited in its use.

Fail:

const value: any = 1;
Enter fullscreen mode Exit fullscreen mode

Pass:

const value: number = 1;
Enter fullscreen mode Exit fullscreen mode

Class Names should be in PascalCase format

Fail:

class carModel { }
Enter fullscreen mode Exit fullscreen mode

Pass:

class CarModel { }
Enter fullscreen mode Exit fullscreen mode

Class Property Definitions

Class properties should be listed before the constructor. Each property should be properly labeled private, protected, or public and listed in that order. Private properties should begin with an underscore and be camelCased. Protected and Public should simply be camelCased. It is preferrable to label public properties as such, but is not exactly required. It's preferred because by default non-labeled properties are considered public. However in C#, non-labeled properties are considered private. I think consistency across our two most used languages would be a good thing to pursue.

Fail:

class CarModel {
    constructor() { }

    TestPrivateProperty = 1;
    TestProtectedProperty = true;
    TestPublicProperty = 'I am public';
    TestPublicProperty2 = 'So am I';
}
Enter fullscreen mode Exit fullscreen mode

Pass:

class CarModel {
    private _testPrivateProperty: number = 1;
    protected testProtectedProperty: boolean = true;
    public testPublicProperty: string = 'I am public';
    testPublicProperty2: string = 'So am I';

    constructor() { }
}
Enter fullscreen mode Exit fullscreen mode

Class Method Definitions

Class methods should be camelCased. Each method should be properly labeled private, protected, or public with the exception of the constructor. It is preferrable to label public methods as such, but is not exactly required. It's preferred because by default non-labeled methods are considered public. However in C#, non-labeled methods are considered private. I think consistency across our two most used languages would be a good thing to pursue.

Also opening brackets are on the same line as the method name, and the closing bracket is on a new line.

Fail:

class CarModel {
    TestPrivateMethod(): number {
        return 1;
    }
    TestProtectedMethod(): boolean {
        return true;
    }
    TestPublicMethod(): string {
        return 'I am public';
    }
    TestPublicMethod2() {
        return 'So am I';
    }
}
Enter fullscreen mode Exit fullscreen mode

Pass:

class CarModel {
    private testPrivateMethod(): number {
        return 1;
    }
    protected testProtectedMethod(): boolean {
        return true;
    }
    public testPublicMethod(): string {
        return 'I am public';
    }
    testPublicMethod2(): string {
        return 'So am I';
    }
}
Enter fullscreen mode Exit fullscreen mode

C

The following rules are based on C#.

Class Names should be in PascalCase format

Fail:

class carModel { }
Enter fullscreen mode Exit fullscreen mode

Pass:

class CarModel { }
Enter fullscreen mode Exit fullscreen mode

Class Property Definitions

Class properties should be listed before the constructor. Each property should be properly labeled private, protected, or public and listed in that order. Private properties should begin with an underscore and be camelCased. Protected and Public should simply be PascalCased. It is preferrable to label private properties as such, but is not exactly required. It's preferred because by default non-labeled properties are considered private. However in TypeScript, non-labeled properties are considered public. I think consistency across our two most used languages would be a good thing to pursue.

Fail:

class CarModel {
    CarModel() { }

    int TestPrivateProperty = 1;
    bool TestProtectedProperty = true;
    string TestPublicProperty = 'I am public';
    string TestPublicProperty2 = 'So am I';
}
Enter fullscreen mode Exit fullscreen mode

Pass:

class CarModel {
    private int _testPrivateProperty = 1;
    protected bool TestProtectedProperty = true;
    public string TestPublicProperty = 'I am public';
    public string TestPublicProperty2 = 'So am I';

    CarModel() { }
}
Enter fullscreen mode Exit fullscreen mode

Class Method Definitions

Class methods should be PascalCased. Each method should be properly labeled private, protected, or public. It is preferrable to label private methods as such, but is not exactly required. It's preferred because by default non-labeled methods are considered private. However in TypeScript, non-labeled methods are considered public. I think consistency across our two most used languages would be a good thing to pursue.

Also, opening and closing brackets are on new lines.

Fail:

class CarModel {
    int TestPrivateMethod() {
        return 1;
    }
    bool TestProtectedMethod() {
        return true;
    }
    string TestPublicMethod()
    {
        return 'I am public';
    }
    string TestPublicMethod2()
    {
        return 'So am I';
    }
}
Enter fullscreen mode Exit fullscreen mode

Pass:

class CarModel {
    private int TestPrivateMethod()
    {
        return 1;
    }
    protected bool TestProtectedMethod()
    {
        return true;
    }
    public string TestPublicMethod()
    {
        return 'I am public';
    }
    public string TestPublicMethod2()
    {
        return 'So am I';
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

This is a work in process document. These standards and guidelines will change and evolve over time.

Discussion (0)