How to Write Highly Scalable and Maintainable JavaScript: Namespacing

Originally published at innoarchitech.com here on September 3, 2014.

Articles in This Series

  1. The “Wild West” Syndrome
  2. Namespacing
  3. Modules
  4. Coupling

Introduction

This is the second chapter in a series on how to write highly scalable and maintainable JavaScript. In the first chapter, we discussed the so-called “wild west” syndrome, the root cause of it, and some potential solutions. This chapter is focused on the namespacing pattern.

Software applications, particularly web and mobile-based, are becoming increasingly JavaScript intensive. A lot of the logic and functionality in these applications has steadily shifted to the client-side.

Consider traditional non-JavaScript server-based functionality that is responsible for an application’s error handling. Depending on the required functionality and complexity, it would typically be implemented as either a separate library (project/dll in .Net), or as a single class under a specific namespace in a service or business layer.

To use this functionality on the server, a consumer would either instantiate an instance of this class, or make service calls to the appropriate layer’s error-handling API. In either case, error handling is a cross-cutting concern and will likely be required by most, if not all application layers.

Now suppose that we want similar error handling capabilities on the client side of a JavaScript-dominant web application. How might we implement this? One way would be to create a single JavaScript file that handles all of our front end code for the given application. This file would include code for “DOM-ready” tasks like wiring up DOM element events, application bootstrapping and state initialization (think AngularJS), declarations (variables, objects, and functions), and any cross-cutting functionality. This approach is obviously monolithic, not scalable, nor maintainable.

A better approach would be a client-side architecture that’s similarly layered and/or modular as compared to our server-side counterpart. Before diving into the architecture, let’s first discuss namespacing in JavaScript applications.

Namespacing in Scalable and Maintainable JavaScript

In the absence of a modular specification like CommonJS or AMD, namespacing is a best practice to avoid global scope pollution and to organize code modules in a logical, scalable, readable, and maintainable fashion.

A top-level application namespace (i.e., object) is often created, and is the only application object that is attached to the global scope object (window object in a web browser, and global object in a Node.js application). Once this namespace is chosen, nested namespacing can be used in conjunction with a modular architecture. For example, consider the following:

Example: Namespaces and sub-namespaces

var myMasterNS = myMasterNS || {}; 
myMasterNS.mySubNS = myMasterNS.mySubNS || {};
myMasterNS.mySubNS.someFunction = function(){ 
// insert logic
};

Here we have declared the top-level global namespace as myMasterNS, and assigned a sub-namespace object as a property of this namespace, mySubNS in this case. Now we’re able to implement any functionality on the top-level namespace and its sub-namespaces without polluting the global scope. Note that the pattern shown is not the only namespacing pattern. I chose it for this example due to its simplicity and readability.

With the server-side analogy, the top-level namespace is similar to the entire application, whereas each nested namespace can be thought of as an individual library, component, or module (e.g., dll in .Net). The modularity in general is the key aspect.

We must ensure that the organizational and architectural considerations and implementations applied to server-based code is also be applied to client-based code. We have done that to some extent in the namespacing example shown.

Summary

In this chapter, we have examined JavaScript namespaces and one way of implementing them. We also discussed reasons to consider using namespaces, and examined some analogies with server implementations.

In the example given, we’ve used namespacing to implement somewhat similar organization, grouping, and layering to our server-side counterparts. We implemented our entire application’s functionality with just one variable attached to the global scope. We're certainly free to implement as many sub-namespaces as we see fit, as well as utilize nested namespaces even on our sub-namespaces, e.g., myMasterNS.mySubNS.mySubSubNS.

The next chapter of this series will cover native JavaScript module patterns, which work very well with namespacing. We will also examine non-native module specifications and formats (e.g., CommonJS and AMD) that are recommended in most cases, while considering cross-cutting concerns and loose-coupling as well.

About the Author: Alex Castrounis founded InnoArchiTech. Sign up for the InnoArchiTech newsletter and follow InnoArchiTech on Twitter at @innoarchitech for the latest content updates.