Being a Better Javascript Developer

I have gone through numerous phases of javascript development, peer reviewed a metric ton of other people’s Javascript and have experimented quite a bit with the old and new Javascript APIs and have found some common things that make code “good”. My aim is to help you be a more thoughtful javascript developer (though the concepts presented will be applicable to development in any language). Let’s get started.

Self Documenting – Write Readable Code

For better or worse, documentation is a lost art. In startups, things are typically moving too fast to spend time documenting something that might be tossed out tomorrow. The issues start popping up when new developers start working on undocumented code. Personally, I am ok with undocumented code, as long as the code is self-documenting. I will illustrate what I mean, with a couple actual examples of code I’ve come across:

function gen(t,s,a){
    var e = document.createElement(t);
    e.setAttribute('style', s);
    for(var i in a){
        e.setAttribute(i, a[i]);
    }
    return e;
}

This code works fine, but it requires more than skimming over to understand what it’s doing. I try to think of not only other developers, but myself when I go back in 6 months to tweak something; code needs to be very easy to read and glean what’s going on. Here is a modified version of our element generator that I believe is more readable:

var element = {
    create: function(tag_type, attributes){
        var el = document.createElement(tag_type)
          , styles = attributes['style'] || []
          , i
          , x
          , style_string = '';

        delete attributes['style'];

        for(i in attributes){
            el.setAttribute(i, attributes[i]);
        }

        for(x in styles){
            style_string += x+':'+styles[x]+';';
        }
        el.setAttribute('style', style_string);
        return el;
    }
}

element.create('div', {
    id: 'foo',
    class: 'bar',
    style: {
        'position': 'absolute',
        'top': 0,
        'left': 0,
        'background-color': '#000'
    }
});

The reasons this approach is preferable are:

  1. element.create is an accurate description of what the method does
  2. The element object leaves room for additional DOM Element utility methods
  3. The parameters are flexible and intuitive and reading the first line of the definition (create: function(tag_type, attributes){ informs you of that with meaningful variable names
  4. Helps avoid stomping on global variables
  5. Namespaced code is inherently more readable

One more thing… can we please start this convention when caching jQuery objects?

<code>var $header = $('#header');</code>

It’s important to cache your jQuery objects if you are using the same selectors over and over again, prefixing that variable with a ‘$’ is a visual cue that the variable is a cached jQuery object.

Know the Libraries you use

Libraries like jQuery, Backbone, Underscore and the like can save a significant amount of development time. People are frequently surprised though that over time the return is diminishing when you don’t really understand what’s going on within the libraries. “Why?”, you may ask; because I’ve seen a thousand examples of people implementing methods that already exist in libraries and not understanding things like $('.selector') requires a moderately expensive DOM lookup every time it is called when caching the result  (var $selector = $('.selector');) is extremely easy and adds much less to the cumulative page load/render process. If you find a library you like, learn it in depth; if you were a book author you probably wouldn’t know the bare minimum about a subject and guess about aspects of it hoping you are accurate, you would research it and develop an expertise.

Level of effort over time

This chart illustrates the hidden cost of not understanding the libraries you are using.

Understand and Adopt the DRY Principle

DRY (Don’t Repeat Yourself) is such an important concept in computer science that receives such little attention. The aim is reducing redundancies and making your code more readable and intuitive. Redundant code is hard to maintain, fragile, and frustrating to debug or augment. There are a couple simple rules I have for employing the DRY concept:

  • If you write something more than once, it probably should be a function/method
  • If you have functionality that is repeated across the entire product, it should probably be in a library or a function (* or as a plugin if you are using a library like jQuery).

In case you are having problems visualizing what this actually means in practice, here is an example:

Example HTML

<code>&lt;form action="/do/something/" id="some_form" method="POST"&gt;
   &lt;input class="required" type="text" name="name" placeholder="Full Name" /&gt; 
   &lt;input class="required" type="text" name="phone" placeholder="Primary phone" /&gt; 
   &lt;input type="text" name="github_url" placeholder="Social Coding URL (github, google code, etc)" /&gt; 
   &lt;input type="text" name="linkedin_url" placeholder="LinkedIn Profile" /&gt; 
   &lt;textarea name="bio"&gt;&lt;/textarea&gt; 
   &lt;input type="submit" value=" Save " /&gt;
&lt;/form&gt;</code>

DRY Version

$('#some_form').submit(function(){
    var $this = $(this),
            $inputs = $form.find('input,select,textarea');

    var empty_required_elems = $inputs.filter(function(){
        var $this = $(this);
        return $this.hasClass('required') &amp;&amp; $this.val() == ""; 
    });
    return !empty_required_elems.size();
});

Redundant Version

$('#some_form').submit(function(){
    var name_value = $(this).find('[name=name]').val();
    var phone_value = $(this).find('[name=phone]').val();
    var github_value = $(this).find('[name=github_url]').val();
    var linked_value = $(this).find('[name=linkedin_url]').val();
    var bio = $(this).find('[name=bio]').val();

    if(name_value == "" || phone_value == ""){
        return false;
    }

    return true;
})

Hopefully you can see that the DRY version is appropriately more concise and easier to maintain.

That’s all for today, let me know how you make your code better in the comments.

Leave a Reply