Svend

Random thoughts about IT

Introduction to clean javascript design

with 3 comments

Despite all the efforts spent to replace it with something more decent (e.g. Flex, DartSilverlight,…), javascript is still today the language of choice for browser-side scripting. And given the huge spotlight that HTML5 is directing on the browser, it becomes again an extremely popular language.

Javascript is powerful and comes with a rich ecosystem. Its major problem though is a syntax so permissive that care is required in order to avoid ending up with a bunch of unmaintainable spaghetti code.

The purpose of this post is to present basic design tips which help keeping things clean and organized. I hope it to be useful for javascript developers struggling with code design or experienced designers struggling with javascript…

Use OO encapsulation

Summary: each concept should be encapsulated inside an object.

OO principles are usually associated with types definition, but they also bring great benefits to dynamically-typed languages like javascript. Failing to encapsulate pieces of functionality inside objects quickly leads to a messy set of unmaintainable procedures calling one another in a chaotic way.

The closest concept to a type in javascript is the prototype, which can be defined programmatically via a constructor, like this:

function User(login) {
  /////////////
  // members
  this.username = login ;
  this.pseudo;
  this.photo = new Photo();

  /////////////
  // public API
  this.updatePhoto = function (photoLink, photoCaption) {
    if (this.photo == undefined) {
      this.photo = new Photo();
    }
    this.photo.apply(photoLink, photoCaption);
  }
}

So that instances of User can simply be created with:

var paul = new User("paul");
var luc = new User("luc");
luc.updatePhoto(photoHost + "/users/luc/profile.jpg", "Mr Handsome");

When designing types, an important guideline to follow is what Robert C Martin named the SRP: Single Responsibility Principle (pdf): each type should have only one responsibility. The SRP can be generalized to any code container at any granularity (function, type, library, file,..), which yields the concept of separation of concerns.

I usually avoid as much as possible inheritance and polymorphism in javascript. Those concepts are feasible (see the OO chapter of Eloquent javascript) but they tend to make the code less maintainable because there is nothing to warn us when a sub-type breaks the contract of its parent (except of course bugs, or thorough unit-testing, but unit-testing for type definition checks really reminds me of EJB2 declarations boiler plate code, and I made promises to myself regarding that…).

A lot has already been written about OO and javascript. For example Suhdhir Jonathan has recently posted a nice introduction to objects in javascript in which he illustrates the usage of the this keyword.

Avoid global scope namespace pollution

Summary: bundle all declarations inside libraries. Librairies should be the only thing declared with global scope.

Declaring too many functions or variables with global scope quickly leads to namespace pollution and introduces a risk of randomly redefining existing components by mistake. This problem may temporarily remain hidden because the browser resets the global scope at every page load so that a web application can survive quite long without being split into libraries.

Javascript does not provide a mechanism specifically designed for librairies, but we can use singleton objects for that purpose, like this:

var myShinylib = {
  makeMarmelade : function (listOfVegetables) {
    // do something relevant with those vegetables here..
  },

  makeJuice : function (oneFruit) {
// put here algo to make juice...
  }
};

Constructors can also be gathered inside libraries, with exactly the same syntax:

var someVegetables = {
  Tomato : function (origin, size, age) {
    // put here the constructo for Tomato
  },

  Potato : function (origin, size, age, kind) {
    // put here the constructo for Potato
  }
};

Now that those constructors and other functions are nicely packaged, they can simply be invoked as follows:

var oneTomato = new someVegetables.Tomato("Chile", 12, 2);
var onePotato = new someVegetables.Potato("Belgium", 2, 2, "Charlotte");
var somethingInteresting = myShinylib.makeMarmelade([oneTomato, onePotato]);

The drawback (but which is also the very purpose) is that we now have to type a fully qualified name for anything (i.e. someVegetables.Tomato instead of simply Tomato), but I believe this is a fair price to pay for avoiding name collisions and improving code durability.

The next question is how to design the content of those libraries? The most sensible response is again to apply the SRP: group inside one library declarations which have one common purpose, which would typically be re-used together and/or which would typically change togheter in case of refactoring.

Use many js source file at development time

Summary: javascript code should be split into several files, potentially many of them.

Each javascript file should contain one logical grouping of declarations. A rule of thumb is to define one library per file, although there can be many good reasons to do otherwise.

A commonly raised objection to this is that a web page loads faster when the javascript code is bundled inside a few big files instead of many small ones. I believe though that this concern is related to production packaging only and should not influence the development style. It can be addressed by post-processing the code before deploying it on production systems, for example with javascript minimizers.

Rely on browser-side MVC and DOM templating

Summary: follow the MVC pattern for browser-side code (in addition to the other MVC you probably also have on server-side) and use templates for creating HTML elements.

MVC is a well known GUI pattern that comes in many flavors (model 1, model 2, MVVM,..). Templating is a mechanism to create views (the V of MVC) dynamically by applying runtime data to generic templates.

A “naked” javascript engine is rather unhelpful for either of those two patterns but several popular librairies exist to help us. Here is the generic MVC construction I currently rely on, based on jquery and knockout:

javascript MVC with Jquery and Knockout

  • Among many other niceties, jquery provides the powerful on method to listen to DOM events (mouseclick, keypressed..). This even works for HTML elements that do not exist yet at the moment of the listener registration.
  • knockout (aka KO) provides an auto-updating HTML templating engine: it listens to changes in KO observable objects and automatically updates accordingly any previously created DOM element.
  •  KO also lets you subscribe to KO events, so for cases where you want to update the DOM yourself, you can use that mechanism to register “custom GUI updaters” (which are possibly based on other templating libraries).

There are other valid approaches and technologies for javascript MVC and DOM templating, for example based on sproutcore, backbone.js and handlebar. It is a good practice to base the application on one or several of them. We should also avoid writing code like the one below because it mixes controller logic with presentation logic:

// try NOT to do that (or at least not too often...)
var painfulDiv = document.createElement('div');
painfulDiv.setAttribute('id','lastCenturyDiv');
painfulDiv.innerHTML = "There are'nt many excuses anymore to create DOM elements like this...";
document.getElementById("zoo").appendChild(painfulDiv);


Leverage functional programming

Summary: functional programming tends to make code more readable.

Functional programming is a powerful way of expressing a process through concise and readable expressions. Investing some time to get familiar with it is very much worth the effort (you may start for example with this introduction).

Javascript does not generally provide built-in implementations for the most commonly used building blocks of functional programming. However, here again, third party libraries exist to address this. Have a look for example at underscore‘s implementation of each, map, filter, find, union, intersection,…

Suppose for example we have an array of users and we want to retrieve one by username. Functionnal programming makes this a one liner:

var user = _.find(users, function(oneUser) {return oneUser.username == 'robert'});

Which is more elegant than looping through the array. Here is an example a bit more involved: suppose we have an array called assets and we want to transform some of the objects it contains depending on their internal state:

var submittedAssets = _(assets).chain()
                               .filter(function (asset) {return asset.isModified})
                               .invoke(adjustStatusIfRequired)
                               .map(function (asset) { return new StaticResource(asset)})
                               .value();
  • line 1 wraps an underscore object around the original array and starts chaining function calls
  • then line 2 lets us specify which subset of the array we want to update (in this case, the ones that are flagged as modified)
  • line 3 applies the adjustStatusIfRequired function on each filtered asset
  • line 4 uses the map function to call the StaticResource constructor on each resulting item and builds a new array with the result
  • finally the .value() of line 5 function is a technicality required to stop the underscore chaining of function calls

Here again, using the for/loop equivalent works fine but is much less clean and readable.

Conclusion

Web application typically need to evolve quickly. Applying the principles exposed here helps to build a modular application where each part can be replaced and re-used without having to redevelop everything every time.

The world or javascript third parties is huge and evolving fast. My examples are based on a small subset of what’s available today and will probably become obsolete faster than the principles they illustrate.  It is important to invest time often to refresh our culture of such libraries, new cool stuff are bubbling up at every moment that make our work easier 🙂

Written by Svend

January 4, 2012 at 10:04 pm

3 Responses

Subscribe to comments with RSS.

  1. Hi Svend,

    As a developer myself, I think that in this post you have changed my mindset about JavaScript being this ugly and non-efficient scripting language to a very clean language.

    The thing is there is just too much bad JS code out there to give it a bad name!

    itoctopus

    January 6, 2012 at 2:34 pm

  2. Svend

    April 6, 2012 at 9:41 am

  3. Introduction to clean javascript design « Svend…

    Thank you for submitting this cool story – Trackback from JavaPins…

    JavaPins

    September 5, 2012 at 6:36 pm


Leave a comment