JavaScript modules

Working with big JavaScript projects

by Krzysztof Winiarski

Big project, big problems

  • hard to read
  • hard to test
  • hard to maintain

Any suggestions how to improve?

  • Standards
  • Modules
  • Automation
Part I

Standards

Improving maintainability with style guidelines

Do we need standards?

Principles of maintainability

Maintainable code is:

  • readable
  • consistent
  • predictable
  • documented
  • testable

Readable code

  • coding conventions
    • indention levels
    • statement termination
    • line length
    • line braking
    • blank lines
    • curly braces
  • naming conventions
    • variablesAndFunctions
    • CONSTANTS
    • Constructors
    • _otherConventions
    • $jQueryCollection

Consistent code

When you establish coding and naming conventions
stick to them!

Ideally code should look as if it was written by the same person.

Predictable code

Avoid complexity and stick to the programing principles

KISS, DRY, YAGNI, loose coupling, separation of concerns, open/closed, single responsibility, IoC

In JavaScript you have to think asynchronous

so it will be better if you are familiar with events, callbacks & promises

Documented code

Why I see you are all embraced?

One of the most important habits, yet hardest to follow.

Testable code

Embraced again?

TDD, BDD... No mater how you name it. What is important you will always write code you only need. Unit test will also warn anyone who will try to brake your implementation.

Part II

Modules

Improving maintainability with modules

Principles of modularity

  • specialized
  • independent
  • decomposable
  • recomposable
  • substitutable

No out of the box solution yet

but we can do this:

  • Object literal notation
  • Module pattern
  • CommonJS modules
  • AMD modules

Object literal notation

In JavaScript functions are first-class citizens and we can make strong use of it.

Example


var myCart = {

  totalAmount: 0,

  items: [],

  placeholder: document.getElementById('#cart'),

  addItem: function (item) {
    this.items.push(item);
    this.totalAmount += item.price;
  }

};
          

Pros

  • Simple implementation
  • Relatively easy to create instances with Object.create

Cons

  • No encapsulation, easy to overwrite property
  • Variables may leak

Module pattern

Lets add closure concept to the object notation.

Example


var myCart = function () {

  var totalAmount = 0,
      items = [],
      placeholder = document.getElementById('#cart');

  return {
    addItem: function (item) {
      items.push(item);
      totalAmount += item.price;
    },
    total: function () {
      return totalAmount;
    }
  };

};
            

But what about dependencies?

Inject dependencies


var myCart = (function ($) {

  return function cart() {

    var totalAmount = 0,
        items = [],
        placeholder = $('#cart');

    return {
      addItem: function (item) {
        items.push(item);
        totalAmount += item.price;
      },
      total: function () {
        return totalAmount;
      }
    };

  };

})(jQuery);
            

How about automatic dependency resolution?

Impossible without additional tools.

Pros

  • Clean and flexible model
  • Relatively easy to create instances
  • Encapsulation
  • Dependency injection

Cons

  • Methods added later cannot access privates
  • Hard to test private parts of module
  • No automatic dependency resolution

So what with this automatic dependency resolution?

CommonJS modules

Modules/1.0

CommonJS implementations

  • Node.js
  • CouchDB
  • RingoJS
  • many more...

Example


var $ = require('jquery');

module.exports = function cart() {

  var totalAmount = 0,
      items = [],
      placeholder = $('#cart');

  var prototype = {
    addItem: function (item) {
      items.push(item);
      totalAmount += item.price;
    },
    total: function () {
      return totalAmount;
    }
  };

  return Object.create(prototype);  

};
            

What about browser?

AMD modules

Modules/AsynchronousDefinition

Not a CommonJS project anymore

AMD API

  • define(id?, dependencies?, factory);
  • define.amd
  • require(dependencies, callback);

AMD libraries

Example

module.js

define('myCart', ['jQuery'], function ($) {

  return function cart() {

    var totalAmount = 0,
        items = [],
        placeholder = $('#cart');

    var prototype = {
      addItem: function (item) {
        items.push(item);
        totalAmount += item.price;
      },
      total: function () {
        return totalAmount;
      }
    };

    return Object.create(prototype);  

  };

});
            
app.js

require(['myCart'], function (myCart) {
 
  var cart = myCart();
  cart.addItem({price: 5});
  
});
            

Compatibility

AMD + CommonJS

UMD

Universal Module Definition

Example


(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else if (typeof exports !== 'undefined') {
    module.exports = factory();
  }
})(this, function () {
  return function cart () {
    // module body
  };
});              
            

This will work in Node.js and in the browser
(with RequireJS for example).

Feature

ECMAScript modules

  • Will be implemented in ECMAScript 6 Harmony
    (aka. JavaScript.next or ES.next)
  • Don't confuse with class - ES.next will have it too
  • Still working draft...

Example

module.js

module Cart {
  import something from otherModule 

  var internalData;
  
  function internalFunction() {}
 
  export function addItem(item) {}
  export function total() {}
}             
            
app.js

import {addItem, total} from Cart;

addItem({ptice: 5});
            

Use Test it today

Controversy

Proposed solution is not compatible with currently adopted solutions like CommonJS or AMD.

Managing modules

  • npm - Node Packaged Modules
  • Bower - A package manager for the web
Part III

Automation

Improve maintainability with automation

Why?

  • Save you time
  • Focus on your code
  • Clean workflow

What?

  • Building deployment packages
  • Code analysis (code lint)
  • Unit tests and code coverage
  • Documentation update

When?

  • development
  • deployment

Building deployment packages

Summary

  • Learn and spreed programing principles
  • Switch on asynchronous thinking
  • Know tools and solutions JavaScript has to offer
  • Write modules, use package manager
  • Automate what you can

Any questions?

The End

Thank you for your attention!

Bibliography

  1. Learning JavaScript Design Patterns by Addy Osmani
  2. A Few New Things Coming To JavaScript by Addy Osmani
  3. JavaScript Module Pattern: In-Depth by Ben Cherry
  4. Maintainable JavaScript by Nicholas C. Zakas
  5. Programming JavaScript Applications by Eric Elliott
  6. JavaScript Patterns by Stoyan Stefanov