JavaScript Architecture

No, that isn’t meant to be an oxymoron. But something I’ve noticed recently is that people’s approach to JavaScript seems to be diverging down two common paths. This blog post is designed to encourage you to adopt the one you probably aren’t planning to adopt right now! The approaches I’m describing are depicted below;

Keep that in mind and we’ll look at each in turn…


What I’ve dubbed “script-on-top” is what I believe most developers do right now. That is, they look to sit JavaScript on top of the HTML and CSS; the script uses the HTML and CSS and manipulates them as though they are components just waiting to be orchestrated. You’ll often see code that looks a bit like this (I’m using jQuery);

   1:  $(document).ready(function () {
   2:      $('#combo').change(function () {
   3:          var value = $(this).val();
   4:          var result = myframework.getDisplayMessageFromServer(value);
   5:          $('#messagediv').html(result);
   6:      });
   7:  });

* Note that none of the script in this post is real. I just hacked it into notepad – but it demonstrates the point sufficiently.

There are some good practices there – not least the fact that the call back to the server is encapsulated within a reusable framework. This is layering, effectively creating a data access layer in JavaScript, and hence is following patterns that have been established for a long time for server-side code. The configuration for how to communicate with the server and the location of the server endpoint is all encapsulated within this framework.

However, I have a few problems with this approach.

1. I don’t like specifying element identifiers in JavaScript. Why? Because it feels wrong. It just does. Stick with me and you might start to agree. Fundamentally this comes down to the separation of concerns between CSS, HTML, and JavaScript.

2. If I have lots of drop-down lists that have very similar behaviour, I still have to wire up every single one. A lot of developers really do wire up every single one manually in code like that above. There are ways to apply behaviour in a blanket manner but none quite so good as my preferred approach… so hold that thought.

3. I don’t like the idea of having to write an entirely new User Interface “manager” component of some description. What often happens with the above approach is that when a page gets more complex developers create a central class that wires up all these events, maybe caches some data, and more. Why? Surely we’re done all that server-side, must I really Repeat myself (R capitalised in homage to DRY) on the client?

4. The URLs to each endpoint are embedded in the framework. But my URLs are “designed” on the server (especially if you’re using Routing, perhaps with ASP.NET MVC)… surely I don’t want to hard-code them in the script too?


So what is the alternative? I believe we need to turn our way of thinking about JavaScript on it’s head. Instead, think of CSS and JavaScript as defining a platform that our HTML mark-up simply refers to in order to build up a user interface. Rather than our JavaScript taking ownership of HTML elements, our HTML makes use of predefined JavaScript “behaviours” (yes, I know that is an emotive term for JavaScript so forgive me!) and CSS styles.

Such a mind-set leads to HTML that looks like this (I’m using ASP.NET MVC 3 with a Razor view);

   1:  <select 
   2:      data-getmessage-output="#messagediv" 
   3:      data-getmessage-source="@Url.Action("Message", "Ajax", new { item = "{placeholder}" })">
   4:  </select>
   6:  <div id="messagediv"></div>

… and matching JavaScript a bit like this;

   1:  $(document).ready(function () {
   2:      $('*[data-getmessage-source]').change(function () {
   3:          var value = $(this).val();
   4:          var url = $(this)
   5:              .data('getmessage-source')
   6:              .replace('{placeholder}', value); ;
   7:          var output = $(this).data('getmessage-output');
   8:          var result = myframework.getDataFromServer(url);
   9:          $(output).html(result);
  10:      });
  11:  });

So what is the difference? The difference is that my JavaScript is a reusable component, and my HTML has output instructions to the client to make use of that component through the use of an HTML 5 Custom Data Attribute. It could easily have used a CSS class instead if the parameters to my component were simpler. The script is slightly longer, but it isn’t complex – and none of it will be repeated in individual pages.

As a result, the URL to the endpoint is no longer hard-coded in a JavaScript library. And all SELECTs that should have this behaviour get it automatically just by referencing this script. The pairing of output DIV and drop-down list is clearly defined in HTML, not tucked away in JavaScript somewhere. There are, in fact, no IDs in my JavaScript, which means that my HTML is completely owning the document structure while JavaScript provides behaviour for that structure… without detailed knowledge of it.

I can still create reusable JavaScript – in fact, my sample code could be hugely refactored into something much more reusable.

But most of all, there is no longer a need or temptation for a central orchestrating JavaScript component – our orchestrating is done by the HTML, which is generated server-side, so our server code is really pulling the strings. We’ve moved our mind-set from writing JavaScript to “make the UI work” into writing HTML that composes reusable JavaScript components and behaviours. The highlight is because I believe that’s a good summary description of what I’d encourage you to do.

Does It Matter?

Yes, I believe it does. Follow this composition approach and your JavaScript code will be easier to thoroughly test (because you won’t have lots of separate wiring up code for each page), and the act of composing will often feel simpler to the developer than writing imperative code to “pull strings” for any particular page.

So, what do you think?

Comments (10)

  1. Colby Africa says:

    Nice decomposition of the problem and I agree.

  2. Matt Hidinger says:

    Hi Simon – good post. I agree with a lot of the ideas presented here.

    I actually used a technique very similar in a post from a few days ago. The article was technically about progressive enhancement techniques (also with MVC 3 and Razor), but my conventions for creating hyperlinks which can open dialog windows and customize the title of the dialog all fit the conventions you describe here.…/Progressive-enhancement-tutorial-with-ASP-NET-MVC-3-and-jQuery.aspx

    Let me know what you think



  3. Erik Schierboom says:

    Very interesting idea, which reflects some of the sentiments I have also had. I have go to great lengths to prevent redeclaring the URLs in my JavaScript. Definitely gonna try this out sometime. My only concern is that the HTML might become cluttered with a lot of attributes that distract from the semantics.

  4. Simon J Ince says:

    @ Matt;

    Nice link. I blogged on PE a while ago too;…/jquery-mvc-progressive-enhancement.aspx

    … but as will be obvious from the sample my ideas have evolved even further since about how that PE should be implemented, hence this post. Great example in yours though, and very nicely walked through.

    @ Colby & Erik;

    Thanks! And interesting point about the cluttering of the HTML. I'll be keen to see if this does become a problem – my suspicion is that having strict rules about HTML formatting and indentation would negate that issue… in many ways, HTML is already very cluttered so I'd hope we could deal with it.


  5. Eric Sowell says:

    This is interesting. It definitely gives me some ideas to think about and definitely has advantages in some scenarios. Will have to explore more, and I mean that, despite what I am about to type 🙂

    I have three concrete examples from my work where the script-as-a-platform-driven-by-attributes approach gives you less control than script-on-top.

    1. If the UI being developed is just plain ol' html pages that needs a re-usable javascript library to make server-side calls or encapsulate logic, putting things in attributes gets you into the same troubles. You now have to start embedding the urls manually in attributes in the page. The only other advantage that applies is that you don't need the id's, but this is not a big advantage. Server-side generated items, usually form elements, will have id's generally anyway.

    2. At work we have a mixed application. The UI guys are building on top of a really crapily done skinning implementation on top of webforms. Now, we could start tweaking the old webforms code to start putting in attributes but at that point we are no longer allowing our UI guys to work independently. Not a problem with the script-on-top approach.

    3. We do a lot of A/B testing of the UI layer. Having to have different server-side code to generate A and another to generate B would be a bad idea, and that would be necessary if you wanted them to behave differently.

    Another reason to consider the script-on-top approach rather than the script-as-a-platform is that it more closely parallels the relationship of css to the markup. The code may be generating the hooks and putting them in attributes, but you are still changing your markup more just to accomodate your script. Or, going further, you are actually changing your markup MORE to accomodate your script this way. That's not necessarily wrong but I like that so much about the css…I want it with my js too 🙂

    Okay, and now for two very short and admittedly pedantic statements 🙂 First, "Script-on-top" is pretty descriptive but "Script-as-a-platform" is not because in my mind it equally applies to both. Of course the the first applies to the latter approach as well. Second, I'm not sure the images convey these concepts well.

    So there are a few cases where the approach you are not advocating wins, IMO.

    Oh, and there is no reason why you couldn't auto-generate some js that defines your routes and have your js reference that, so you can still get away with not hard-coding your routes in your js files.

    But interesting post. Like I said, will be experimenting some.

  6. Simon J Ince says:

    @ Eric;

    interesting points – I certainly think your point (2) is food for thought, in that non-greenfield development will be more difficult to port to my "platform" approach.

    As for (1), that is easily counteracted if necessary, perhaps by having a data-retrieve-data-type="person" attribute, which means the framework code knows how to go and get that data, what the URL is, etc… I quite like having the URLs in mark-up, but I see your point.

    As for (3) I don't know enough about this to comment 🙂

    I intentionally named it "Script-as-a-platform" because I wanted to evoke emotional feelings and mental pictures of using JavaScript functionality in the same way as you might a browser, or .NET, or similar – so I disagree that the Script-on-top approach shares those qualities. Note I'm referring to your own custom Script when I call it script-as-a-platform… obviously you could argue jQuery or JavaScript itself is a platform for your script, but that's not what I'm trying to get at.

    Wow, I just confused myself with that last sentence, so if you're still following well done 😮


  7. Eric Sowell says:

    The whole embed url in script or html is really a non-issue because you could use the same techniques to avoid doing that going both directions. Instead of embedding the url, you could embed the same metadata in the js objects you create and they can dynamically build the url, or look it up through some kind of server-generated javascript, or other x way of avoiding this…if it is an issue worth avoiding.

    I am actually not convinced that it is for most apps. But, if you need the flexibility, you can go that route. As a general rule, I would rather embed the url first, and only in one place, by default. That makes everything quite readable. More readable than if the url is generated or inferred. In my experience the real problem is not embedding the url, it is embedding it multiple places. That makes for all kinds of maintenance hell.

    As for the naming, I believe I shall call my approach scripting-with-kittens as everyone likes the image invoked emotionally by kittens and therefore will have positive feelings towards my view 🙂 If you want to argue that the approach of layering js functionality in through the script-on-top approach is not platform-y, you have quite a ways to go before you can make that distinction. Can it be reusable? Absolutely, because I put those abstractions in an external js file and reference that when I need it. Do the calling pages need to know the internals of the js object to complete the task? No, so it has good encapsulation. As a matter of fact, all the page needs is to know how to gather the inputs it wants to use, pass them in, and deal with the result in the way it wants to deal with them. Of course the standard way of dealing with reusable components generally.

    So, I must say that I don't follow your reasoning on this 🙂

  8. Simon J Ince says:

    @ Eric,

    LOL about scripting-with-kittens. Why didn't I think of that?

    As for URLs, I agree 100% – there should be a single version of the truth, not multiple "embeddings", which is why I think that truth should be the routing table on the server, which should emit the relevant URL into the HTML to help the script along when needed.

    As for the layering, I'm not saying you shouldn't layer and componentise JavaScript – I'm just trying to switch the mind-set around of what that script and its layers do. Once we have that approach right, layering and reuse are hugely important.


  9. CJ says:

    Have you looked at Knockout which is an MVVM pattern for javascript.

  10. Simon J Ince says:

    @ CJ;

    I have, briefly, and other similar approaches, and they're very interesting. They certainly hugely improve the structure of a lot of JavaScript. But I feel like that is going even further down the "script-on-top" route, so isn't really compatible with wait I'm aiming at here…