Namespaces are Old School
Let’s start with an overly simplified/generalized and mostly wrong history of the JS community during the past decade.
Let’s go back in time 12 years, to the distant year of 2000. JavaScript is being mostly used for form field validation, analog clocks and mouse trails. Nobody really cared about namespace cluttering, all the code resided on the global scope. This is considered the dark age of JS.
Now let’s fast forward 5 years, to the the first stage of the JavaScript Renaissance (2005-2007); libraries like jQuery, Mootools and Prototype.js are getting extremely popular, AJAX is the buzzword of the moment. Augmenting native prototypes was a very common practice and no caution was taken into consideration, the rule of thumb was easy development and brevity. Larger projects started being developed by more people and best practices started to appear. Sometime around this period closures became a popular way of hiding information and IIFE became the De facto standard. Namespaces also became really popular.
Now back to 2012. Everybody knows that augmenting built-in native objects is a bad thing, specially host objects. Polluting the global namespace is also considered a bad practice and many people avoid it as much as possible. It is not uncommon to see people adding their own application code into objects that they don’t own, proving that they don’t really understand why they shouldn’t have globals to begin with, but at least we are moving towards the right direction. <rant>Polluting any namespace is a BAD thing, not only the global scope, you should NOT put your application code into the $
object…</rant> Script loaders and package managers are becoming more popular each day, node.js is the buzzword of the moment and Harmony might become a reality and provide a native module format.
OK, no more history… Let’s see some code.
Why Namespaces?
Namespaces were created as a way to avoid name collisions and to group code by context. Some variable/function names are very common and it is very easy to get into conflicts. Keeping all your code inside a sandbox reduces this chance, it also improves the code organization.
Namespaces in JavaScript
The language doesn’t provide any special keyword to define a namespace so it’s a common practice to use plain objects as a way to emulate it.
var myNamespace = {}; myNamespace.bar = 'this is dog fort'; myNamespace.doFoo = function(){ console.log(myNamespace.bar); };
That is a valid way to group methods by context and to avoid name collisions. And it’s been working for the past 10+ years for the JS community, except when it doesn’t.
Verbosity
After you get neurotic about name collisions and/or the libraries/frameworks grow to a certain size it is inevitable that you have nested namespaces like lorem.ipsum.dolor.doSomething()
which isn’t fun, specially if it is a method that you use very often.
Namespace cluttering
To avoid the verbosity many libraries started to put all methods inside a single object, jQuery and Underscore.js are famous examples of this poor practice. The chance of name collisions increases a lot, and naming methods becomes harder. Just imagine 2 jQuery plugins that implements the same method with different behavior (plugins are evil BTW), chaos will ensue.
An object with too many methods probably has very low cohesion and that is an anti-pattern. The code gets harder to browse and inspect since everything is mangled into the same object, the namespace should give context to its properties. A method add()
inside a userList
object probably means “add a new user to the list”, while a method with the same name inside a FOO
object can mean hundreds of different things.
Code sharing
A common practice that I’ve seen is to create a global object named as the company/project name. So if the project is for a client named “Foo” the whole application code would be placed into the FOO
object. Now if you want to reuse the same code into multiple projects you will need to replace every reference to the FOO
object or keep all the shared code into a separate namespace. This doesn’t scale really well and is error prone…
noConflict()
Everything goes well with the namespaces until 2 libs decide to use the same name, or you need to load 2 versions of the same library into the same page. The solution, create a noConflict()
method. Now every library that don’t want to create conflicts with 3rd-party code needs a noConflict()
method. That is not ideal and extremely error prone, specially when code is loaded asynchronously or you have a large code base with a complex dependency tree.
var _oldNamespace = window.myNamespace; // reset global reference to previous state myNamespace.noConflict = function(){ window.myNamespace = _oldNamespace; return myNamespace; };
It’s 2012, use a module system!
What is the best way (using current JS) to really solve the global name conflicts? Don’t use globals at all!
With a module system like AMD or CJS you don’t rely on globals, you use IDs to reference other modules.
define(function(require, exports){ var foo = require('foo'); var ipsum = require('lorem/ipsum'); exports.bar = function(){ foo.doFoo(); ipsum.log('amet'); }; });
If for some reason you have conflicting code you can simply map the IDs to point to a different location:
requirejs.config({ map : { '*' : { // most modules will load foo.1.0 'foo' : 'lib/foo.1.0' }, 'bar' : { // the module "bar" will load a diff version of "foo" 'foo' : 'lib/foo.2.0' } } });
Namespaces becomes obsolete when you are able to require specific modules and/or functions. This also favors smaller modules that consumes fewer dependencies, increasing cohesion and improving the code organization. With a module system, global variables becomes almost unnecessary.
If you still think AMD isn’t useful you are probably writing code like if it was 2005. I moved to AMD almost 2 years ago and it feels great to not have to type awkward namespaces, not have to worry about name collisions, have a smart build system that inlines only the modules that are currently being used, don’t have to worry about the code execution order, being able to load other kinds of resources besides JS, lazy load code if needed, etc… Some of my past projects had more than 500 source files (JS + templates) and I have to say that AMD made the development process infinitely easier. Code sharing increased exponentially and multiple developers could work together without causing conflicts. If you think it’s too much boilerplate to type on each file create a code snippet and assign some shortcut, problem solved. #winning
If you avoid named modules and use relative paths it becomes really easy to share code between projects, no renaming and/or configuration needed. Let your build script name your modules for you (the RequireJS optimizer is great for that).
Namespaces are old school; Welcome to the module era.