Thursday, January 3, 2013

Structuring A Clientside JavaScript Application

World's largest bowl of spaghetti
... or how I wrote JavaScript the first half of my career

A lot of this will seem like common sense to some, but I have on many occasions seen very good developers write some pretty poorly structured JavaScript apps (including myself, haha), and I've been asked about it a few times recently, so I'll give it a shot. I hope to go over most of what I know in this arena.  There is a good amount to go over, but I'll try to hit the most important basics.

Use A JavaScript Bundler/Minifier/"Compiler"

Probably the biggest and most important thing to do with a large JavaScript client application is to give yourself the ability to separate your code out into individual files each containing code with a single responsibility without during your user experience with a ton of .js files to download.  The best way to do that is by using a tool to take your individual JavaScript files and compile them into a single JavaScript file (minified or un-minified). Fortunately, there are a lot of tools for doing this. Notably tools like UglifyJS and the build tool Grunt, ASP.Net MVC4's new Bundling and Minification features, extensions for Visual Studio like Mindscape Workbench.  They all offer a variety of features, some of them will even do things like run JSLint against your code or kick off unit tests in various JS testing frameworks.  The important features you're looking for is "bundling" or concatenation, and minification.

Use the Module Pattern

The module pattern is something that has been covered extensively all over the web, and probably better than I could do it, but the basics of the module pattern is to use JavaScript closure in an immediately executed anonymous function to contain all variables and functionality that you want to remain private to a set of code. You can do tons of stuff with this pattern, and it really saves you from junking up your global scope, be it a module in NodeJS or the window object in a browser. I recommend wrapping your practially your whole JS file in the module pattern specifically because then you're guaranteed to know what you're adding to the global scope, because you've done so explicitly.

So basically you're looking at something like this:
;var myModule = (function($, foo) {
    //here $ and foo are local to the scope.

    //here's some private variable.
    var bar = 123;

    //here's a private function
    function superThing() {
       alert('Bar is ' + bar++);

    /** You can alter injected objects to
        effect the outside **/
    // here we'll alter the jQuery object by adding a plugin.
    $.fn.superPlugin = function() {
       $(this).on('click', superThing);
    // same as above but we're removing a binding here.
    $.fn.removeSuperPlugin = function() {
       $(this).off('click', superThing);

    /** You can have it return an interface 
        to whatever it's doing **/    
    return {
        incrementBar: function () {
        callSuperThing: function (){
})(jQuery, foo);

Note: So what's the ; for in the module above? Basically to keep bundlers and minifiers from combining two function calls into one function call, causing errors: (function(a,b){})(c,d)(function(w,x){})(y,z)

Structure Your Files Appropriately

Think of your class files or code files in your usual programming language of choice: C++, Java or C# for example. You're breaking your code out into files based on single responsibility. (Or at least I hope you are). You should be doing the same with your JavaScript files. Because you're bundling them or building them into a single file prior to hosting them, you now have the freedom to structure your JavaScript files however you want.

An example of such a file structure might be (for an Angular app for example):

  | +-Directives
  | | +-my-click-directive.js
  | | +-table-directive.js
  | | +-directives-module.js
  | |
  | +-Controllers
  | | +-HomeCtrl.js
  | | +-SearchCtrl.js
  | | +-FooCtrl.js
  | |
  | +-Services
  | | +-facebook.js
  | | +-twitterSearch.js

... you get the idea. But the point is that in the end, it doesn't matter how many files you have, as long as you can easily maintain and organize them. The alternative is to have the one JavaScript "mega-file" which I've seen way too many times.

But, How Do I Debug Bundled Or Minified Files?

This actually isn't as bad as you'd think. Some of the packages, MVC4's bundler for example, will actually output individual files when you're in debug mode. Other bundlers will tack some whitespace and a comment in with the name of the file where concatenations have been done. This is helpful if it's not minified. Also if it's not minified, your comments will show up, and if you've added good comments, and you know how you've structured your app, it shouldn't be a huge leap to find the offending lines of code in your source while you're debugging.

But what about if the file is minified? Well, now you're in for it, I guess. However, some browsers, such as Google's Chrome actually have a feature to "prettify" minified code to so you can step through it in a readable format. (In Chrome this feature is a little button with a {} in it in your developer's console)


Another really great way to get an idea on how to structure your JavaScript code is too look at examples presented by others. They are all over the place these days! Just think of your favorite JavaScript framework or library and check them out on GitHub: JQuery, Angular, Ember, etc. All really awesome examples of how to effectively structure your JavaScript code and files.