Making the Best of a Bad Architecture

My latest project involves layering some advanced functionality on top of an existing app that'd been built with a Bootstrap and jQuery "framework" from Theme Forest. The architecture is a loose collection of a couple dozen jQuery plugins, each loaded on to the page via their own script tag, some of which were checked into the repo and some of which were on a CDN, along with a bunch of script tags sprinkled throughout the EJS templates.

The limits of what could be accomplished with that setup were hit immediately. At this point lots of developers would insist upon rewriting things from scratch, and I definitely struggled with the temptation to do that myself. The problem with that course of action is that I don't know enough about the users and their needs to do that properly in the time available. This app has to be ready by the end of July in order to be presented at a trade show in August, along with a marketing site I'm also building.

Time to make the best of what we got.

The last few weeks have been spent reinforcing the existing structure in order to make it possible to add new functionality without sacrificing what's already there.

The plugins previously loaded via CDN were brought into the codebase like all the rest. And Grunt was added to the workflow to concatenate all the plugins together, then minify them. Doing so has reduced twenty nine requests totaling 707 kb to one request of 509 kb.

Backbone was chosen to handle the new functionality because it can bind to elements that have been rendered on the server, and do so without getting in the way of the existing plugins. Since the server is an Express app we can use npm to install Backbone, and Browserify to package the new app code together while keeping it all organized cleanly in modules.

At this point we've got two app bundles, one for the old code and one for the new code. Everything seemed good to go except for one frustrating catch… now there's two copies of jQuery.

If you've been here before then you know one solution is to use browserify-shim to defer to an existing jQuery. It does so by transforming the `require('jquery')` statement when browserify is run. However, Backbone has its statement wrapped in a try/catch block that browserify-shim wasn't smart enough to work with. Ain't nobody got time to write a patch so a workaround was needed instead. Putting the following line in the app.js entry file is all it takes:

var$=window.$=window.jQuery=require('jquery')

Now everything plays nicely together. Those preexisting sprinkles of functionality are being pulled into the new framework bit by bit, and we're on track and on budget to launch at the end of July.