Darcy Clarkebuilding products / experiences / communities & culture

Toggle Main Navigation

Jan 24, 2011

Javascript Applications 101

Posted in "development"


One of my favorite things to do is to build Applications and their inner workings. Scalability and robustness are two things I keep in mind when beginning development. Javascript has become the "go-to" language for Application development these days so it's important to get a good understanding of how to develop a good base for your application to grow on. I'll let you see how I start my Applications and give you tips as to why.

If your interested in building large scale applications you should also check out @addyosmani's blog where he goes into detail about the different resources and philosophies you should keep in mind (http://addyosmani.com/blog/large-scale-jquery/).

Namespaces/Aliases

Be a good citizen of the web and of your project. Don't begin taking up all the global namespaces willy nilly. Javascript is object oriented and you should use that to your advantage. Pick a global namespace and stick with it. Here are a few good examples as far as naming conventions go: "Core", "App", "Site" etc. I personally always use App. It makes a lot of sense and is less geeky then saying "Core". Here's what it looks like.

var App = {}`</pre>
You'll notice that "App" will be my only variable and is instantiated with an Object Literal. As we build you'll begin to see how nice and tidy everything is by keeping it within a single namespace. Believe me, you'll thank me later.

Moving on, we need to begin to build a structure for our application to run in. We'll need to create an initialization and destruction method to neatly take care of any processes that need to happen at either.
<pre class="brush:js">`App.init = function(){
    // Initialize
});

App.destroy = function(){
    // Destroy
});`</pre>

### Publish / Subscribe

The above code may look very familiar if you've read my blog before. I wrote library agnostic version of "PubSub" (Publish / Subscribe [http://darcyclarke.me/development/library-agnostic-pubsub-publish-subscribe/](http://darcyclarke.me/development/library-agnostic-pubsub-publish-subscribe/)) which we'll be incorporating here in a second. I bring this up only to note that keeping your Applications primary initialization and destruction methods outside of a Pub/Sub environment will keep things orderly and shows the importance of those events.

Looking ahead it's necessary for us to create a loose coupling system that will be able to setup receivers that will execute processes we pass to them at different times through out our application. This is definitely a reusable system and I heavily maintain that if you aren't using PubSub or something similar in your applications that you are bound to fail. Let's look at the code:
<pre class="brush:js">`App.subscribe = function(name, callback){
    App.subscriptions.push({"name": name, "callback": callback});
    return [name,callback];
},
App.unsubscribe = function(args){
   for(x=0;x<App.subscriptions.length;x++){
        if(App.subscriptions[x].name == args[0], App.subscriptions[x].callback == args[1])
            App.subscriptions.splice(x, 1);
    }
},
App.publish = function(name, args){
    var temp = [];
    if(App.subscriptions.length > 0){
        for(var x=0;x<App.subscriptions.length;x++) {
            if(App.subscriptions[x].name == name)
                temp.push({"fn":App.subscriptions[x].callback});
        }
        for(x=0;x<temp.length;x++){
            temp[x].fn.apply(this,[args]);
        }
    }
};`</pre>
Adding this now brings a robustness to our application that can be used in many facets throughout. Let's go back to our init and destroy methods and add in a publish listener.
<pre class="brush:js">`App.init = function(){
    // Initialize
    App.publish("init");
});

App.destroy = function(){
    // Destroy
    App.publish("destroy");
});`</pre>
With this in place we can now cleanly bind other processes to the initialization and destruction of our application. This is the essence of "loose coupling". Now that we have a base we need to include some dynamic functionality to our app in order to pass and receive data from our server or REST API.

### AJAX

AJAX is the name of the game these days. You can't have a web application without having to communicate with third party services. Google Maps, Twitter, Facebook everyone has an API and it's important to the success of your web application to have one as well. Since we won't be going into the server side part of a REST API I should note that there are many scalable options to hosting your data but ultimately it is how you query and receive that data which will determine it's usefulness.

The example I've put together is fairly tightly coupled with jQuery. That said, the implementation is such that you could easily mimic it for whatever other library you would be using. As well, I've gone ahead and made the method fairly robust to allow for common published success and error events along with two paramaters to execute subsequent callback functions for either a successful or unsuccessful request.
<pre class="brush:js">`App.ajax = function(service, data, success, failure){
        $.ajax({
            type: "post",
            url: App.url + "/api/" + service,
            data: data,
            dataType: "json",
            success: function (data) {
                App.publish("ajax_request_success");
                success(data);
            },
            error: function (request, status, error) {
                App.publish("ajax_request_success");
                failure(request, status, error);
            }
        });
    };`</pre>
The `App.url` variable will get set up at the top of our App declaration and will be a useful variable to have to use in other methods. This function could, again, be built out a bit more to be even more robust but for now it's definitely a flexible solution that allows you to funnel all requests through.

An example usage of this is below:
<pre class="brush:js">`App.ajax("users", { action:"update", username:"darcy" }, function(data){
            console.log(data);
        }, function(request, status, error){
            console.log(error);
        });`</pre>
You can see that I pass in the service "users" which will subsequently ping my server at "http://domain.com/api/users" with the data action = "update" and username = "darcy". I log the returned data in both my success and error callbacks. Pretty straightforward but very flexible.

### Libraries

Don't be ashamed to use a Javascript library. They are there to help you. It's estimated that 3,000 of the top 10,00 sites on the web use jQuery alone and again, there may be more that are "hiding" their use.

That said, you should make sure not to rely on said libraries. Loose coupling is the name of the game here and creating levels of abstraction is key to being able to manage and scale your application long term. There may come a time when you need to switch from jQuery to Prototype for whatever reason and having code in place that is library specific will be detrimental and costly in that transition.

In my Applications I try and loosely couple jQuery as much as possible relying on it for triggering events. Let's look at my key integration point and uses.
<pre class="brush:js">`jQuery(function($){
    App.init();
});

jQuery(window).unload(function(){
    App.destroy();
});`</pre>
The above illustrates my primary integration points with jQuery. When the document, or DOM, is ready we trigger the apps `init()` method and when the window is being unloaded we call the subsequent `destroy()` method. This is good practice to keep in mind. You can go on to add other triggers for event binding but the idea of loose coupling should always be in mind and most  snippets should all look very similar.

An example of an binding to an event and publishing said function, using our Pub/Sub methods before:
<pre class="brush:js">`// Subscribe to Event
App.subscribe("play", function(e, this){
    e.preventDefault();
    App.play(this.src);
});

// Bind to Event and Publish functions
$(".play_btn").bind("click", function(e){
    App.publish("play", [e,this]);
});`</pre>
In this example we subscribe to the "play" event and then execute the play even when a click event is triggered on the `.play_btn` element.  You should also take note of the parameters being passed to the subscribed functions through the`publish()` method. This is a great way to pass instances such as this.

### Bringing it all together

Let's see what it looks like all together as a base to our application.
<pre class="brush:js">`/*************************************************************************/
/* Application
/*************************************************************************/

    var    App = {};
    App.url = "http://domain.com/";

       App.init = function() {

           App.publish("init");

       },
    App.destroy = fucntion(){

        App.destroy("destroy");

    },
    App.subscribe = function(name, callback){
        App.subscriptions.push({"name": name, "callback": callback});
        return [name,callback];
    },
    App.unsubscribe = function(args){
        for(x=0;x<App.subscriptions.length;x++){
            if(App.subscriptions[x].name == args[0], App.subscriptions[x].callback == args[1])
                App.subscriptions.splice(x, 1);
        }
    },
    App.publish = function(name, args){
        var temp = [];
        if(App.subscriptions.length > 0){
            for(var x=0;x<App.subscriptions.length;x++) {
                if(App.subscriptions[x].name == name)
                    temp.push({"fn":App.subscriptions[x].callback});
            }
            for(x=0;x<temp.length;x++){
                temp[x].fn.apply(this,[args]);
            }
        }
    },
    App.ajax = function(service, data, success, failure){
        $.ajax({
            type: "post",
            url: App.url + "/api/" + service,
            data: data,
            dataType: "json",
            success: function (data) {
                App.publish("ajax_request_success");
                success(data);
            },
            error: function (request, status, error) {
                App.publish("ajax_request_error");
                failure(request, status, error);
            }
        });
    };

/*************************************************************************/
/* Subscriptions
/*************************************************************************/

    App.subscribe("init", function(){
        alert("Hello World!");
    });

    App.subscribe("destroy", function(){
        alert("Leaving so soon?");
    });

/*************************************************************************/
/* Events
/*************************************************************************/

    // DOM Ready
    jQuery(function($){
        App.init();
    });

    // Window unload
    jQuery(window).unload(function(){
        App.destroy();
    });

Hope this helps you get off to a good start with your application development and I'll be sure to post more on this subject in the coming months as some of my own projects start to roll out.