The JavaScript Old Guard

I’m perhaps just in the right age bracket to both appreciate and disagree with the recent drama around JavaScript Fatigue. On the one hand, things were just plain simpler back in, say, 2005-2010 than they are now. On the other, things also kinda sucked back then.

JavaScript in 200X

In 2005 I was just starting my career as it is today doing web development. What tools did we have to work with? You’re thinking jQuery, but you’d be wrong since it wouldn’t be released for another year in mid-2006.

This was the era of Prototype, MooTools, and shudder ExtJS. This was also the dawn of the big frameworks like Rails and Django, so for the most part we had PHP, JSP, ASP and the like generating pages and adding some dynamism with essentially just ad-hoc scripts.

Then, finally, came jQuery which smoothed over a lot of the ugliest code. But it’s still just ad-hoc scripting. Taking a page and cutting it up, adding event listeners to do AJAX calls and then updating the DOM directly with the results, etc.

Whether jQuery or Prototype, these ad-hoc scripts were, let’s be honest here, monstrosities. Maintaining them after the fact was a nightmare, and refactoring pretty much consisted of a re-write every time. These days it’s hard to even think of a use-case for this kind of code. Fortunately, I still have some (prepare yourself)!

Bugrocket is a project I started in 2009 to replace Bugzilla at work. It’s still running today, however it really needs some JavaScript refresh work done. The problem is that the entirety of the front-end code is this jQuery soup that is completely daunting to try and refactor piece by piece. Here’s a sample:

$('.delete_list').singleClick( function() {
  var link = $(this);
  var listId = link.parents('form').attr('rel');
  var modal = $('.modal#list_' + listId + '_modal');
  var ticketCount = $.ajax( {
    url: '/tickets/' + listId,
    dataType: 'json',
    async: false,
    success: function( r ) {
      if( confirm( 'Are you sure? All tickets (' + r.count + ') ' +
                   'will be deleted as well!' ) ) {
        $.ajax( {
          url: '/lists/' + listId,
          type: 'DELETE',
          data: null,
          dataType: 'json',
          success: function( r ) {
            modal.trigger('hideModal');
            if( r.ok ) {
              $('ul.lists li[rel=' + listId + ']').remove();
              $('.empty_done').remove();
            }
            else {
              alert( r.error );
            }
          }
        } );
      }
      else {
        modal.trigger( 'hideModal' );
      }
    }
  } );
  return false;
} );

Well, that’s embarrassing. The file that code is in is called org.js and it includes pretty much all of the imperative/event handling code needed to wire up the overall settings page for a Bugrocket account. It’s about 500 lines long, all like the code above.

There’s drag and drop code, file upload code, modals opening/closing, spinners, ACL list management stuff, user editing, on and on.

The effort required to go back and revisit this feels like the kind of effort it would have taken to put in place a proper set of tools to begin with — if they had existed, of course.

Other places in the codebase aren’t so bad, where I’ve organized the various functionality into rough class-like boxes and call things like TicketList.init(). This definitely makes it easier to follow the code, but with no prescribed way to do anything, it’s all just whatever-made-sense-at-the-time.

Production-build-wise, at this point, we pretty much just have a concat step at best. Just put your dependencies first and then all the rest of your files stuck on the end. Then you might minify it.

JavaScript in 201X

Around 2010 things started to change. Angular appeared but didn’t get much attention at first. Bigger news was the arrival of Backbone.js.

Wow, what a difference it made. While still pretty flexible, it was a lot clearer what you should use Backbone’s Model, View and Controller for. Taking a bit of time to learn what these 3 important pieces are and what they can be used to do meant the resulting code was much easier to maintain and new co-workers much easier to onboard.

In my own code around this time, I was fully on board with Backbone (and CoffeeScript) and it resulted in code that I find fairly maintainable to this day.

Ultimately you’re doing very similar stuff to the jQuery soup. But it’s all nice and namespaced. Every part of your app handles its own stuff internally. If you want to change something about how the user edit stuff in the account settings behaves, there is only one obvious place you need to look.

Basically it means that, knowing just the basics of Backbone, you can understand and follow the code.

There are still plenty of warts at this point. For example Backbone Models and Views are generally attached to each other by event listeners. It’s tempting to have App.someThing be some global instance of a Backbone Model, and simply change it in response to the user doing things. Then whatever views care about App.someThing simply do stuff in their change listener. This sounds good, but in reality is makes it pretty hard to know at any given moment who is changing the data.

Another even bigger problem is that quickly your Backbone View’s grow into a monstrosity of their own doing individual DOM updates in response to every possible change that could ever happen. There’s a great deadpan cartoon from LispCast that explains this problem and how React solves it:

From this post.

Around this time and over the next few years we start to see libraries and frameworks that use ‘2 way data binding’ getting popular such as Ember.js and Knockout. Personally, I never got on board due to major performance problems at the time (these days it’s fine). Also, while it abstracts away the view rendering/update problem, it doesn’t really do much for sane dataflow.

For production builds we start to see more automated and handy tools such as Grunt/Gulp/etc showing up and making it easier to use transpilation (CoffeeScript for example), minification, and gzipping. That’s cool!

JavaScript Today

Today we have not only all of the previous stuff in various updated forms (such as Angular which eventually took off) but also crazy new stuff like React.js and Flux that fundamentally changes how we can approach front-end code.

There’s a whole ecosystem of these new tools, just like there was when Backbone.js came out, and it’s sometimes pretty daunting to know where to begin.

To make matters worse the build-system aspect has also been growing and evolving this whole time. Now we have Webpack and the like which not only do what the previous tools did but add to that things like hot reloading and dead code elimination.

And…?

That’s great, you’re thinking, but it doesn’t help me sift through the massive towering pile of stuff I feel like I need to learn!

sorry :)

My point is merely that it’s always been complicated. You don’t need to learn every new thing that appears just because it’s being hyped on Twitter. If you’ve got some pain points in your current toolset, see if some of this fancy new stuff can help you, but definitely don’t start re-writing your app every time a new Flux implementation appears.

Personally my favourite way to pick up this new stuff is by doing small toy projects for fun that use new things in a ‘safe environment’. I’ll be writing more about that soon. Sign up for my newsletter and I’ll let you know when I do!