Blogging about our lives online.


Skratch Development Update

"Make one to throw away"

I forget who said this, but it has been good advice for my little web-based sketching app called Skratch. After the first version was up and running I took a step back and had a hard look at the overall structure.

Overall it wasn't too bad. It has been a work in progress to figure out how to modularize and encapsulate. In the alpha stages it was a bunch of global functions and variables going every which way. By version 0.1, I had realized that I needed to introduce some structure and so I grouped the drawing code into objects with attributes. Most of the event handling code was still in global functions. At this point I took a break and did some reading.

First I read Douglas Crockford's JavaScript: The Good Parts, and none of it really sunk in. It's an excellent book for the theory of how to use the language functions and how to avoid bad practices, but it doesn't really give the reader a sense of how they should write JavaScript. All of the examples are very short and specific to a certain language feature.

Then I read the jQuery source code and realized that I hadn't got it at all. It took me a while to really grasp what was going on here, and most of that time was spent trying to figure out what it was that I didn't understand. The thing that I didn't understand was simple but elusive: closure.

I have heard of closures as a programming concept a number of times but I never really grasped why they would be practically useful or how I would recognize one when I saw one. Reading the jQuery source, it took me a while to realize that this was a ~6000 line closure staring me right in the face. So I started coding to see how I could use an anonymous function to my benefit.

It's really quite simple: any vars, functions or objects declared inside a function are only accessible within that function. So if an anonymous function invokes itself, it's totally possible to not add to the global namespace at all. Nothing within that function is accessible unless it is attached somehow to the global namespace. But those functions that ARE attached to the global namespace can make use of all the private variables and state within the anonymous function.

This is the little testing function that I hacked together to prove this to myself:
(function () {
    var obj = {}, 
        privateData = 42,
        privateMethod = function (arg) {
            return "Private method: called with "+ arg + 
                    "\n" + "The holy grail: " + privateData + "  sees:" + obj.globalData;
    //Priveledged: public methods which rely on private members.
    obj.protectedMethod = function (arg) {
        return "Priveledged method: called with " + arg + "\n" +
                    privateMethod("really " + arg);
    // Public: members that are publicly accessible, rewritable, etc...
    obj.globalData = "I am the viewable data of the globalobject.";
    obj.generateString = function () {
        return "Global method: " + obj.globalData + "\n" +
                obj.protectedMethod("do this");
    genericObj = obj;

Only in the last line do I "publish" the object I've created, anything else is encapsulated in the closure and remains private.

Once I grasped this concept, it was immediately apparrent how it would be useful to my drawing app. I created an object, called "skratch" and attached only the functions and data that need to be accessible from outside to it; basically just the UI controls and a .setupCanvas method. The drawing engine and event handlers are now completely wrapped inside the closure.

This way of programming seemed kind of ugly to me until I looked at the DOM tree for my app. There was only one global object called "skratch" with a couple methods for triggering UI events and that was it.

So, I now know what closure is and what it can do for me and I think my scripts will be better for it.

Oh, and FYI, after reading the jQuery source, I couldn't help but include it in my app, even though all it does right now is make the toolbar go swoosh! Totally worth it!

No comments:

Post a Comment