Front-End Code Quality @ Panaya

In Client side we code in ?

LET'S FOCUS ON

In shorts

     used to create interactive websites

SOME FACTS

  • Was written in 1997 over the span of 10 days by Brenden Eich
  • Intends to take us a step beyond static HTML
  • IT'S NOT JAVA
    • an implementation of the ECMAScript SPEC
    • each browser implements the engine as it sees fit
  • NO COMPILER
    • oh what fun...

SO JAVASCRIPT

  • lacks conformity between browsers
  • has no compiler to help us
  • full of "gotchas" that silently introduce bugs
  • Is not java... yet most programmers code like it is...

EXAMPLES

DAMN BROwSER

(function() {

   var a = "initial";
   if(a) {
       function f() { console.log("1") };
   } else {
       function f() { console.log("2") };
   }
   f();

})()

What would be printed

1 ?

2 ?

Internet Explorer

 

1

Chrome

 

 

2

Opera

 

MORE TO FEAR FROM

console.log(typeof greet);
greet();

var greet = function() {
   alert("hello!");
}
console.log(typeof greet);
greet();

function greet() {
   alert("hello!");
}

VS.

EQUALITY using == operatrtor

> 0 == false
    true
> 1 == true
    true
> 2 == true
    false
> 2 ? true : false
    true // because 2 !== 0
'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

Let's focus on these

Let's see

'0'  ==  0  ==  ''

true

true

Remember "Transitivity" property?

X = Y   and   Y = Z     than    X = Z

You'd expect: 

'0' == ''

So ?

'0' == ''

false

DO YOU WANT TO REMEMBER THIS ?

SILENT FAILURES

if(undefined = "foo") {
    ...
}
//OH NO YOU DIDN'T!!

WE JUST RAN OVER "undefined" !!!

NO EXCEPTION WILL BE RAISED

IE8

And So MANY MORE...

USE A "LINTER" :)

STATIC CODE ANALYSIS

 

"Lint" tools read your source code and look for common mistakes...

 

 

 

It will not make you a better coder ;)

 

(function() {
   var a = "initial";
   if(a) {
       function f() { console.log("1") };
   } else {
       function f() { console.log("2") };
   }
   f();
})()

LINT WILL GENERATE AN ERROR DURING BUILD

(compile time)

 "NO INNER FUNCTION DECLARATION" 

Remember this ?

CONTENDERS

  • JS-LINT
  • JS-HINT
  • Closure Linter

WINNER: ES-LINT

TREND

SO WHY ESLINT

  • It's more flexible (~140 Rules, all can be turned off)
    • We are currently monitoring ~40
  • It's blazing fast
  • It's actively maintained and developed
  • AND IT'S EXTENSIBLE
    • Soon - angularJS rules !

SHOW ME THE MONEY

Let's go over Rules

eqeqeq

NEVER USE ==  or != operator

USE === or !=== operators

if (x == 42) { ... }

if ("" == text) { ... }

if (obj.getStuff() != undefined) { ... }

no-use-before-define

// NO !
alert(a);
var a = 10;

// NO !!
foo();
var foo = function() { alert('foo') }


// This is OK
bar();
function bar() { alert('bar') }

variable & function declarations are "hoisted"

HOISTED ?

HOISTING

// SCOPE START HERE
foo();

var foo = function() {
    alert('bar');
}
// SCOPE START HERE
var foo;
foo();

foo = function() {
    alert('bar');
}

Is actually this

JavaScript use (mysterious) "declaration hoisting"

 

All function and variable declarations are moved to the top of their containing scope :\

curly

if (a === b) return;

while(bar)
    baz();

if (foo) {
    baz();
} else qux();

Agreed - this is a "stylistic" rule

Yet - it is well established that common style increase readability and decreases errors

if (a === b) {
    return;
}

while(bar) {
    baz();
}


if (foo) {
    baz();
} else {
    qux();
}

NO

YES

Despite a population of over a billion, China has only about 200 family names.

strict



if(undefined = true) {
   ...
}
// OMG - you did it again


someVariable = "some string"
// notice - I forgot to add var - THIS IS GLOBAL !


delete Object.prototype;
 // throws a TypeError
'use strict'

and many more - silent failures / security considerations / etc...

How do we invoke ?

Just put 'use strict' at the top of scope

function foo() {
'use strict'
    if(undefined = 10) { // generates error :)
        ...
    }
}
function foo() {
'use strict'
    if(undefined = 10) { // generates error :)
        ...
    }

    function bar () {
        // no need to put an extra 'use strict'
        ...
    }
}

No need to use in inner scopes...

AND IF I...

// this is a dummy util file :|
var Utils = {

    foo: function() {
        'use strict'
    },
    
    bar: function() {
        'use strict'
    },

    baz: function() {
        'use strict'
    },    
}

in GLOBAL SCOPE

'use strict'
var Utils = {

    foo: function() {
    },
    
    bar: function() {
    },

    baz: function() {
    },    
}

Not a good idea 

As JS code is concatenated...

 

Basically - this is forcing every JS file to respect 'use strict'

 

ALSO - 3rd party libs :\

in OBJECT DEFINITION

// Like this than ?
var Utils = {
    'use strict'
    foo: function() {
    },
    
    bar: function() {
    },

    baz: function() {
    },    
}

NOPE

In JS - scope is by "function"

 

 

So in fact this is the same as global scope

 

Use this Pattern

// :)
var Utils = function() {
    'use strict'
    return {
        foo: function() {
        },
        
        bar: function() {
        },
    
        baz: function() {
        }
    }
}() // <- PAY ATTENTION TO THIS !

This pattern also enabled to add "private" members in Utils object

// :)
var Utils = function() {
    'use strict'

    var lookAtMe = "I'm Private";

    return {
        foo: function() {
        },
        
        bar: function() {
        },
    
        baz: function() {
        }
    }
}() // <- PAY ATTENTION TO THIS !

You KNOW THIS - ng

angular.module('panaya.common.directives')
    .directive('horizontalDateProgressBar', [function () {
        'use strict';
        return {
            restrict: 'A',
            templateUrl: 'sometemplate.html',
            scope: {
                injectedItem: '='
            },
            link: function (scope) {

                ...
                function bar() {
                    // no need for use strict
                }
                var baz = function() {
                    // no need for use strict
                }
            }
        };
    }]);

no-console

console.log("Made it here.");
console.error("That shouldn't have happened.");

Why not ?

Use of console is considered for debugging purposes only

 

not suitable to be shipped to customer 

 

 

no-redeclare

var a = 3;
// code code code
var a = 10;

No need to explain these

no-unused-expressions

"Hello world";

0

if(0) 0

{0}

f(0), {}

The international telephone dialing code for Antarctica is 672.

no-array-constructor

Array(500)


Array(500, 1, 2)

What's the differance

So - these are confusing notations...

 

Again - Stylistic rule - but considered almost a universal opinion

 

Actually - use of the Array constructor is considered bad practice unless for sparse matrix

// Build Array of 500 objects


// Build Array of 3 and init with values

consistent-return

function doSomething(condition) {

    if (condition) {
        return true; // return boolean
    } else {
        return; // return undefined
    }
}

no-unreachable

function foo() {
    return "bar"
    var baz = "Oh No"; // Will we reach this point ?!
}

Yeah - you can write this in JavaScript

There are 293 ways to make change for a dollar.

JAVASCRIPT

Has alloooot of pitfalls

Yet - it's a really cool language, still evovling

FORMALITIES

  • You can find our list of rules: *HERE*
  • You can find HOWTO's: *HERE*

Currently - during "Compile" stage

  • LINT is turned on as warnings

From "Day after 10.3 branch" (End of April?)

  • LINT will FAIL THE BUILD

I am sending list of errors every Sunday to TL

Thank you

PANAYA - DEV - LINTING PREVIEW

By Amir Gal-Or

PANAYA - DEV - LINTING PREVIEW

Describing "Front-End" code quality tool in Panaya

  • 767