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.
string googleAnalyticsScript = @"var _gaq = _gaq || ;
_gaq.push(['_setAccount', '" + googleAnalyticsKey + @"']);
var ga = document.createElement('script');
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script');
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
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.
var websiteSetup = new WebsiteSetup()
GoogleAnalyticsKey = "GoogleAnalyticsKeyFromDatabaseSetHere"
The snippet above will generate the following JSON string:
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.
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.
- 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.
- 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.
- Reduced payload – JS can be minified to save bandwidth, unified to reduce HTTP requests, and obfuscated as desired.
Programming is the art of telling another human what one wants the computer to do.
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!
Do you find this approach useful? Have another way you solve this? Chime in via the comments below.