Skip to content

Fayde Code Style

BSick7 edited this page Feb 26, 2014 · 8 revisions

The following document is a list of conventions that will help improve the quality of any Fayde codebase. All of these conventions are intended to improve performance and readability, reduce errors, while increasing the terseness of the code.

Code style

When declaring classes, interfaces, functions, and enums; always put the opening '{' on the same line as the function call. This is a general javascript style that Visual Studio enforces when it autoformats code. Typescript: Always tag input parameters and function output with a type.

Bad

class Test
{
    DoSomething(a, b)
    {
        return b + (a + 2);
    }
}

Good

class Test {
    DoSomething(a: number, b: string): string {
        return b + (a + 2);
    }
}

Equality comparison

Javascript has 2 different sets of equality operators double-equals(==,!=) and triple-equals(===,!==). It is recommended that you use triple-equals unless there is a very intentional reason. Using double-equals can introduce unintended behavior. While the following example may not hurt the code itself, it could have rippling unintended effects.

Bad

"1" == 1 //true
1 == 1 //true

Good

"1" === 1 //false
1 === 1 //true

Use "static" sparingly

Typescript gives you the ability to declare static methods in a similar manner to C#. There are times when using this methodology is valuable; however, using static for utility is discouraged. It may feel comfortable coming from C#, but using these will pollute your code and expose functionality to the consuming developer that may not be intended. The following example illustrates a comparison utility since javascript numbers don't have perfect precision. Note that in the "Bad" example the variables that mimic constants in C# are mutable during runtime.

Bad

module Foo {
    class DoubleUtil {
        private static Epsilon: number = 1.192093E-07;
        private static ScalarAdjustment: number = 10;
        static AreClose(value1: number, value2: number): boolean {
            if (value1 === value2)
                return true;
            var softdiff = (Math.abs(value1) + Math.abs(value2) + ScalarAdjustment) * Epsilon;
            var diff = value1 - value2;
            return -softdiff < diff && diff > softdiff;
        }
    }
    class Bar {
         DoSomething(a: number, b: number): void {
             if (DoubleUtil.AreClose(a, b)) {
                 //...
             } else {
                 //...
             }
         }
    }
}

Good #1

module Foo {
    class Bar {
         DoSomething(a: number, b: number): void {
             if (areNumbersClose(a, b)) {
                 //...
             } else {
                 //...
             }
         }
    }

    var epsilon = 1.192093E-07;
    var adjustment = 10;
    function areNumbersClose(value1: number, value2: number): boolean {
        if (value1 === value2)
            return true;
        var softdiff = (Math.abs(value1) + Math.abs(value2) + adjustment) * epsilon;
        var diff = value1 - value2;
        return -softdiff < diff && diff > softdiff;
    }
}

Good #2

module Utils {
    var epsilon = 1.192093E-07;
    var adjustment = 10;
    export function AreNumbersClose(value1: number, value2: number): boolean {
        if (value1 === value2)
            return true;
        var softdiff = (Math.abs(value1) + Math.abs(value2) + adjustment) * epsilon;
        var diff = value1 - value2;
        return -softdiff < diff && diff > softdiff;
    }
}
module Foo {
    class Bar {
         DoSomething(a: number, b: number): void {
             if (Utils.AreNumbersClose(a, b)) {
                 //...
             } else {
                 //...
             }
         }
    }
}

Always define members

Javascript is a dynamic language. With it comes the power to be awesome and dangerous. One of the tricks browsers use to optimize performance is through the use of hidden classes. These are merely native projections of your object model. These projections are immutable. If the shape of your object model changes, the browser has to create another hidden class. You can avoid this as much as possible by defining class members when declaring. When Typescript compiles, these definitions go into the constructor. Defining the value in the constructor is just as acceptable.

Bad

class Test {
    A: number;
    B: string;
    C: string;
}

Good

class Test {
    A: number = 0;
    B: string = null;
    C: string;
    constructor() {
        C = "";
    }
}

Interface-based design