Becoming a JavaScript ninja

I’m training really hard to become what some people call a “JavaScript Ninja”. in this post I will share with you some important things that I have learned so far.

Grayfox.jpg

 1. Use code convections

Coding conventions are a set of guidelines for a specific programming language that recommend programming style, practices and methods for each aspect of a piece program written in this language. These conventions usually cover file organization, indentation, comments, declarations, statements, white space, naming conventions, programming practices, programming principles, programming rules of thumb, architectural best practices, etc. These are guidelines for software structural quality. Software programmers are highly recommended to follow these guidelines to help improve the readability of their source code and make software maintenance easier.

There are tools that will help you to ensure that you and your team follow JavaScript code convections:

Code convections tool Description
JSLint JSLint is a JavaScript program that looks for problems in JavaScript programs. It is a code quality tool. It was developed by Douglas Crockford. JSLint takes a JavaScript source and scans it. If it finds a problem, it returns a message describing the problem and an approximate location within the source. The problem is not necessarily a syntax error, although it often is. JSLint looks at some style conventions as well as structural problems. It does not prove that your program is correct. It just provides another set of eyes to help spot problems. You can download it from www.jslint.com.
JSHint JSHint is fork of JSLint that was created by Anton Kovalyov because he believes that a code quality tool should be community-driven and because he thinks that sometimes we should be able to decide if we want to follor or not one code convection. As a result of this JS Hint is much more configurable than JS Lint. You can download it from www.jshint.com.

 2. Document your code

I’m sure you are tired of listen to people that tells you that you should document your code.I’m sure you are doing it but sometimes is not that easy to find value on doing it but If after creating the comments you end up with a documentation website, something like MSDN or the Java Documentation it seems to be more valuable, fortunately we also have tools that will generate the documentation for us:

Documentation generation tool Description
JsDoc Toolkit Is an application, written in JavaScript, for automatically generating template-formatted, multi-page HTML (or XML, JSON, or any other text-based) documentation from commented JavaScript source code. You can download it from here.

 3. Separate concerns

In computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program.

The value of separation of concerns is simplifying development and maintenance of computer programs. When concerns are well separated, individual sections can be developed and updated independently. Of especial value is the ability to later improve or modify one section of code without having to know the details of other sections, and without having to make corresponding changes to those sections.

In a JavaScript application your concerns are HTML, CSS, JavaScript configuration code and JavaScript logic code. To keep them separated you just have to stick to the following rules:

a) Keep your HTML out of JavaScript: Embedding HTML strings inside your JavaScript is a bad practice.

Embedding HTML strings inside your JavaScript is a bad practice.

var div = document.getElementById("myDiv");
div.innerHTML = "<h3>Error</h3><p>Invalid email adress.</p>";

The best way to avoid this problem is to load the HTML from the server via AJAX ore even better load HTML client-side templates from the server. There are tools like handlebars.js that will help you to generate HTML in the client-side without embedding HTML strings inside your JavaScript.

// rendering logic
RenderJson = function(json, template, container) {
    var compiledTemplate = Handlebars.compile(template);
    var html = compiledTemplate(json);
    $(container).html('');
    $(container).html(html);
};

// remplate
var template = "{{#each hero}}<tr><td>{{this.name}}" + 
    "<td></tr>{{/each}}";

// model
var json = {
    hero : [
        { name : 'Batman' },
        { name : 'Superman' },
        { name : 'Spiderman' }
    ]
}

// Invoke rendering logic
RenderJson(json, template, $('#heroes_tbody'));

// DOM where we will insert HTML on rendering
<table>
    <thead><tr><th>Hero</th></tr></thead>
    <tbody id="heroes_tbody">
        <!-- rows added with JS -->
    </tbody>
</table>

b) Keep your CSS out of JavaScript

Don’t change CSS rules from JavaScript, try to only work with CSS classes.

// bad
$(this).css( "color", "red" );

// good
$(this).addClass('redFont');

c) Keep your JavaScript out of CSS

Don’t use CSS expressions, if you don’t know what is a CSS expression (An IE8 and earlier feature) then you are in the right way.

d) Keep your CSS out of HTML

Don’t use style tags to apply styles, use always class.

e) Keep your configuration code out of your logic code

Try to encapsulate all the hard coded variables and constants in a configuration object..

var CONFIG = {
    MESSAGE : {
        SUCCESS :"Success!" 
    },
    DOM : {
        HEROE_LIST : "#heroes_tbody"
    } 
};

// bad
RenderJson(json, template, $('#heroes_tbody'));

// good
RenderJson(json, template, $(CONFIG.DOM.HEROE_LIST));

If you do this finding the cause of issues will be much easier, imagine an incorrect background error, if you know that there is no JavaScript or HTML touching your CSS, then you automatically know that the issue must be in one of the CSS files, you just need to find the CSS class affected and you are done.

 4. Avoid global variables

In computer programming, a global variable is a variable that is accessible in every scope. Global variables are a bad practices because it can lead to situations when one method is overriding and existing global variable and because code is harder to understand and mantein when we don’t know where the variables has been declared. The best JavaScript code is the one where no global variable shas been declared. There are a few techniques that you can use to keep things local:

To avoid global one of the first things that you have to ensure is that all your JavaScript code is wrapped by a function. The easiest way of doing this is by using an inmediate function and placing all of your script inside of the function.

(function(win) {
    "use strict"; // further avoid creating globals
    var doc = window.document;
    // declare your variables here
    // other code goes here
}(window));

The most common approcach to avoid globals is to create one unique global for your entire application think for example the $ in Jquery. You can then use then a technique known as namespacing. Namespacing is simply a logical grouping of functions under a singleproperty of the global.

Sometimes each JavaScript file is sismply adding to a namespace, in this case, you should ensure that the namespace already exists.

var MyApp = {
    namespace: function(ns) {
        var parts = ns.split("."),
            object = this, i, len;
        for(i = 0, len = parts.lenght; i < len; i ++) {
            if(!object[parts[i]]) {
                object[parts[i]] = {};
            }
            object = object[parts[i]];
        }
    return object;
    } 
};

// declare a namespace
MyApp.namespace("Helpers.Parsing");

// you can now start using the namespace
MyApp.Helpers.Parsing.DateParser = function() { 
    //do something 
};

Another technique used by developers to avoid globals is the encapsulation in modules. A module is a generic pirce of functionality that creates no new globals or namespaces. Instead all the code takes place within a single function that is responsible for executing a task or publishing an interface. The most common type of JavaScript modules is Asynchronous Module Definition (AMD).

//define
define( "parsing", //module name
        [ "dependency1", "dependency2" ], // module dependencies
        function( dependency1, dependency2) { //factory function

            // Instead of creating a namespace AMD modules 
            // are expected to return their public interface
            var Parsing = {};
            Parsing.DateParser = function() { //do something };
            return Parsing; 
        }
);

// load a AMD module with Require.js
require(["parsing"], function(Parsing) {
    Parsing.DateParser(); // use module
});

 5. Avoid Null comparisons

The special value null is often misunderstood and confused with undefined. This value should be used in just a few cases:

a) To initialize a variable that may later be assigned an object value

b) To compare against an initialized variable that may or may not have an object value

c) To pass into a function where an object is expected

d) To return from a function where an object is expected

There are cases in which null should not be used:

a) Do not use null to test whether an argument was supplied.

b) Do not test an uninitialized variable for the value null.

The special value undefined is frequently confused with null. Part of the confusion is that null == undefined is true. However, these two values have two very different uses. Variables that are not initialized have an initial value of undefined.

//bad
var person;
console.log(person == undefined); //true

The general recommendation is to avoid using undefined at all times.

I guess that you must be know wondering how should you do the following without using undefined or null?

//bad
function doSomething(arg){
    if (arg != null) {
        soSomethingElse(); 
    }
}

Comparing a variable against null doesn’t give you enough information about the value to determine whether is safe to proceed. Furtunately, JavaScript gives youi a few ways to determine the true value of a variable:

a) Primitive values: If your expecting a value to be a primitive type (sting, number, boolean) then the typeof operator is your best option.

// detect a number
if(typeof count === "number") {
    //do something
}

b) Reference values: The instanceof operator is the best way to detect objects of a particular reference type.

// detect a date
if(value instanceof Date) {
    //do something
}

**c) Functions: Using typeof is the best way to detect functions.

// detect a function
if(MyApp.Helpers.Parsing.DateParser typeof === "function") {
    MyApp.Helpers.Parsing.DateParser();
}

d) Arrays: The best way to detect arrays is to use the isArray() function. The only problem is that isArray does not work in old versions of internet explorer. But you can sue the following code for cross browser support.

function isArray(value) {
    if (typeof Array.isArray === "function") {
        return Array.isArray(value);
    } else {
        return Object.prototype.toString.call(value) === "[object array]";
    }
}

e) Properties: The best way to detect a property is to use the in operator or the hasOwnProperty() function.

var hero = { name : 'superman '};
//chech property
if (name in hero) {
    // do something
}
//chech NOT inherited property
if (hero.hasOwnProperty('name')) {
    // do something
}

 6. Handle errors

Throwing custom errors in JavaScript can help you to decrease your debugging time. It is not easy to know when you should throw a custom error but in general errors should be thrown only in the deepest part of your application stack. Any code that handles application-especific logig should have error-handling capabilities. You can use the following code to create your custom errors:

function MyError(message){
    this.message = message;
}
MyError.prototype = new Error(); //extending base error class

Is also a good idea to chek for specifict error types (Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError) to have a more robust error handling:

try {
    // Do something
} catch(ex) {
    if(ex instanceof TypeError) {
        // Handle error
    } else if (ex instanceof ReferenceError) {
        // Handle error
    } else {
        //Handle all others
    }
}

 7. Don’t modify objects that you don’t own

There are things that you don’t own (objects that has not been written by you or your team)

a ) Native objects (e.g. Object, Array, etc.)

b ) DOM objects (e.g. document)

c ) Browser object model (e.g. window)

d ) Library objects (e.g. Jquery, $, _, Handlebars, etc.)

And thing that you should not try on objects that you don’t own:

a ) Don’t override methods

b ) Don’t add new methods

c ) Don’t remove existing methods

If you really need to extend or modify an object that you don’t own, you should create a class that inherits from it and modify your new object. You can use one of the JavaScript inheritance basic forms:

a) Object-based Inheritance: an object inherits from another without calling a constructor function.

var person = {
    name : "Bob",
    sayName : function() {
        alert(this.name);
    }
}
var myPerson = Object.create(person);
myPerson.sayName(); // Will display "Bob"

a) Type-based inheritance: tipically requires two steps: prototypal inheritance and then constructor inheritance.

function Person(name) {
    this.name = name;
}

function Author(name) {
    Person.call(this,name); // constructor inheritance
}

Author.prototype = new Person(); // prototypal inheritance 

 8. Test everything

As the complexity of JavaScript applications grows we must introduce the same design patterns and preactices that we have been using for years in our server-side and desktop applications code to ensure high quality solutions. So it is time to start writting tests (unit, performance, integration…) for your JavaScript code. The good news is that there are several tools that you can use to help you:

a) Jasmine

b) JsTestDrive

c) PhantonJS

d) QUnit

e) Selenium

f) Yeti

g) YUI Test

 9. Automate everything

Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.

Continuous Integrations doesn’t get rid of bugs, but it does make them dramatically easier to find and remove. In this respect it’s rather like self-testing code. If you introduce a bug and detect it quickly it’s far easier to get rid of.

Continuous Integration has been used for a while together with TDD (Test Driven Development). But it was more traditionally linked to server-side code. In the previous point we said that it is time to test our JavasCript code. In this point I want to highlight that it is also time to continuous integrate it.

Build

In a professional development environment you will normaly find the following types of build:

a) Development Build: Run by developers as they are working, it should be as fast as possible to not interrupt productivity.

b) Integration Build: An automated build that run on a regular schedule. These are sometimes run for each commit, but on large projects, they tend to run on intervals for a few minutes.

c) Release Build: an on-deman build that is run prior to production push.

Continuous integration

There are serveral continuous integration servers but the most popular is Jenkings, the most popular build tool is apache ant. The process of building your JavaScript code includes several taks:

a) Test automation As discussed on point 8 you should use test automation tools for testing your JavaScript code.

b) Validation You should add code quality validation to your build process. You can use tools like JSLint or JSHint

c) Concatenation You should join all your JavaScript files in one single file.

d) Baking You can perform tasks like adding a code the license or version code as part of the build.

e) Minification You should integrate as part the build the minification by tools like uglify.js.

f) Compression You should gzip your JavaScript as part of your build.

g) Documentation You should integrate as part of your build the auto-generation id the dosumentation by tools like JS Doc Toolkit.

 10. Find a great master

A real ninja never stop learning, so you better find a great master!

pai-mei1.jpg

Where can you find one? The answer is of course the Internet. I recommend to read the blogs of some of the chome or mozilla developers about javascript as well as other js libraries like jquery.

 
101
Kudos
 
101
Kudos

Now read this

Introducing InversifyJS 2.0

A powerful IoC container for JavaScript apps powered by TypeScript I released InversifyJS 1.0 about a year ago. Back then it had some nice features like transient and singleton scope but it was far from what I wanted to achieve.... Continue →