JavaScript Configuration Object Pattern | Flippin' Awesome

By Cory House

So you’re building a modern web app? That means you’re likely running a variety of client-side libraries and custom business logic in JavaScript. One of the first hurdles you run into is, “Hey, I need some data from the server injected in my JavaScript.” Some developers, when posed this problem, have an unproductive response: They start dynamically generating strings of JavaScript on the server so they can inject custom logic onto the page.

No surprise. This is arguably the path of least resistance. But as we’ll see below, it’s toxic because it’s hard to maintain. And it’s not performant. And…okay, let’s hold off on the justification for a second and review a concrete example.

Injecting Server-side Data Into JavaScript

Imagine you’ve built a content management system that is run by multiple clients. Each client configures their Google Analytics Key within an admin console, which you then save to the database. Ultimately, this data needs to be injected into JavaScript. One approach is to build the entire Google Analytics script in a string on the server and inject it onto the page. It looks like this in C#:

string googleAnalyticsScript = @"var _gaq = _gaq || [];
    _gaq.push(['_setAccount', '" + googleAnalyticsKey + @"']);
    _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script');
    ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ?
    'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(ga, s);
    })();";

Note how hard this is to read. Since the entire script is now stored in a string on the server, it’s a wall of text with no code coloring except for the googleAnalyticsKey variable that’s being injected into the script. There’s a variety of other issues with this approach that we’ll get to shortly.

Configuration Object Pattern

Thankfully, a much cleaner option exists using what I call the JavaScript configuration object pattern. Begin by placing the static JavaScript in a .js file. Use variables as placeholders for any dynamic data:

View this on JSFiddle

Note the reference to websiteSetup.GoogleAnalyticsKey above on line two. Where’s that data defined? We define it separately by creating a data structure on the server and serializing it to JSON using a library. As we’re about to see, this is trivial since virtually all popular programming languages have libraries for serializing objects to JSON. Let’s take a look at how we pull this off in C#.

First, define a class called WebSiteSetup with the necessary properties. In this example we only need a single property to store the Google Analytics Key, but the idea scales well if you have a complex dataset to inject.

public class WebsiteSetup
{
    public string GoogleAnalyticsKey;
}

Alternatively, in C# you could simply serialize an anonymous type, and, with a single value like this, that arguably makes the most sense.

Once you’ve defined your type, use a JSON serialization library on the server to convert an instance of this type into JSON. In C#, there are many JSON serialization libraries but in this example I’ll use JavaScriptSerializer since it’s shipped with the .NET framework.

var websiteSetup = new WebsiteSetup()
{
    GoogleAnalyticsKey = "GoogleAnalyticsKeyFromDatabaseSetHere"
};

var json = new JavaScriptSerializer().Serialize(websiteSetup);

The snippet above will generate the following JSON string:

"{\"GoogleAnalyticsKey\":\"GoogleAnalyticsIdFromDatabaseSetHere\"}"

Now it’s just a matter of injecting this string into the head of your page. This piece will vary depending on your server-side technology, but in ASP.NET WebForms you’d do something like this:

var websiteSetup = "var websiteSetup = " + json + ";";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "WebSiteSetupScript", websiteSetup, true);

The idea here is simple: inject the data that your static .js script will need into the head of your page. Just make sure this JSON is injected before your static .js script. The beauty of this approach is we’ve separated our concerns. Configuration data is separate from the definition of the static third party script. And we’ve gained many other benefits, as we’ll see below.

JavaScript belongs in .JS Files

So yes, there are a few more moving parts here, and going through these extra steps to inject a single piece of data into a small script that Google provides may seem like overkill to you. But imagine you’re building client-side charts that require dozens of datapoints from the server for configuration and rendering. Then this approach really shines.

Regardless, chances are you’ll need a variety of data from the server on page load for various JavaScript files. Defining a single setup object that contains all this data allows you to keep all static JavaScript within .js files. The big rule here is to stay native. By native, I mean JavaScript belongs in .js files, not some string written in a server-side language. There’s a variety of benefits to staying native by using the configuration object pattern above.

  1. Separation of concerns – Client-side code should be written *directly* in a client-side language: JS. Avoid using a server-side language to generate JS in a string. Instead, inject dynamic JSON which should be created by serializing a server-side type with a library. This is the approach outlined above.
  2. Caching - JavaScript files are cached by browsers, saving bandwidth and reducing subsequent page load times. In contrast, dynamic JS is downloaded on every server request. So strive to minimize the amount of dynamic JavaScript you send to the client by keeping static and dynamic JavaScript separate.
  3. Avoids string parsing overhead – Dynamic JavaScript requires the server to render the strings of JavaScript on every page request. Rendering a small snippet of JSON that only contains the dynamic data minimizes string parsing overhead.
  4. Code coloring – Note how much easier it is to read the clean native .js file than the string example we reviewed at the beginning of the post. The IDE colors variables, operators, strings, and function declarations separately which aids comprehension.
  5. Syntax checking – If you make a typo writing native JavaScript, your IDE will help you out by underlining the mistake. And you can only enjoy intellisense support when writing native JavaScript in a .js file.
  6. Reusable - The separate .js file makes it trivial to utilize elsewhere. JavaScript written in a string on the server-side is less likely to be reused.
  7. Reduced payload – JS can be minified to save bandwidth, unified to reduce HTTP requests, and obfuscated as desired.
  8. Less abstraction – Building dynamic JS via strings adds a confusing abstraction layer. The reader has to understand both the string parsing rules of the server-side language and JavaScript. This extra layer of abstraction hinders comprehension and maintenance. While the computer doesn’t mind, the maintenance programmer will certainly struggle. Remember:

    Programming is the art of telling another human what one wants the computer to do.

    Donald Knuth

StackOverflow Example

StackOverflow uses the configuration object pattern as well. Visit StackOverflow.com and view source. Search for StackExchange.init(. They simply serialize an object to JSON so that their .JS files have the dynamic data necessary to perform the desired client-side behavior. So hey, we’re in good company here.

Clean Code is for Humans

This conversation is a sampling of the topics I cover in my new Pluralsight course “Clean Code: Writing Code for Humans”. If you’re interested in becoming a better developer and building a vocabulary for evaluating code quality, give it a look!

This article was originally published at http://www.bitnative.com/2013/10/06/javascript-configuration-object-pattern/