Posts Tagged ‘ unobtrusive javascript ’

Dev vs. Dev: Arguments For and Against Unobtrusive Javascript (UJS) [updated]

Friday, March 7th, 2008

Shouting MatchUnobtrusive Javascript (UJS) is defined in Wikipedia is the practice of abstracting Javascript code to separate function from presentation. To grossly simplify things, it means completely replacing all in-line and page-embedded JS with header or externalized code that uses the DOM to access elements by reference.

To use a grossly simplified example, let’s say you have a button that pops up a window on the onclick event. Traditionally, this would be accomplished in-line as follows:

<input name=”myButton” type=”button” onclick=”window.open(‘somepage.htm’, ‘someWindow’,’ width=200, height=300′)” value=”Hola Mundo” />

To make this conform to UJS, one might put the following in an external file:

window.onload = function()
{
  var myBtn = document.getElementById(“myButton”);
  input.onchange = function()
  {
  window.open(‘somepage.htm’, ‘someWindow’,_
          ’width=200,height=300′);
  }
}

This would allow you to strip the inline code from the button, leaving only the following:

<input name=”myButton” id=”myButton” type=”button” value=”Hola Mundo” />

Again, this is an overly-simplified example, but it illustrates the concept. In real practice, UJS has some very practical use. In a world where AJAX apps and JS frameworks are more and more prevalent, teams are larger, and sites live on for years, adhering to professional coding standards becomes increasingly important. The days of copying crappy JS snippets off the web somewhere and cramming them into your web page are over (thank goodness).

That said, use of UJS isn’t without controversy. Specifically, it’s consideration as a ‚Äúbest practice” is not agreed upon by many. While the benefits of abstracting JS code make sense in certain cases, some argue that the overhead associated with UJS makes ongoing maintenance more difficult, and the time to implement the initial code take longer.

In this article, I’m trying a little experiment. Rather than sit here and pontificate on what I think, I thought I would invite some ‚Äúguest speakers” to weigh in and provide varying points of view. My goal is to let you, the reader, decide if UJS is a practice you should adopt.

For the purposes of this exercise, I’ll be taking the side ‚Äúagainst” UJS (though my actual opinion on its use is somewhere in between) and Scott Fegette, the Technical Product Manager for Dreamweaver at Adobe, will be taking the side ‚Äúfor” its use. Along the way, distinguished members of the Development Community will weigh in.

First, it is my pleasure to introduce Scott. As mentioned above, Scott has a thing or two to say about the technical direction of Dreamweaver. Before joining the Dreamweaver team, he was both a Flash Video evangelist and an engineering manager on the Macromedia web team responsible for building the site infrastructure, services and architecture that delivers Adobe.com to this day.

Before joining Macromedia in 2000, Scott spent 6 years building his skills at web design and development from it’s very inception as the director of online services at former Santa Barbara-based software developer MetaCreations- contributing both global site design and server-side framework code, and managing a team of 8 designers and developers to support the site.

Aside from speaking around the globe on web development, web standards, video production and online communities, Scott’s also a professional musician and independent photographer / videographer in his off-hours.

I needed to be convinced of the benefits of unobtrusive JS, and it took me quite a while to come around to the light, so to speak.

From an abstract level, the separation of content/data (HTML/XHTML), design (CSS) and behavior (Javascript) has long been the foundation of the MVC (model, view, controller) model for engineering. This is admittedly more important for team development/design than an individual who wears all the hats, but essentially why HTML selectors (IDs, classes) were created- to target page elements with both design and behavior, and abstract the design/behavior layers into discreet resources that could be worked on independently of the content itself.

Look at it this way- we already have embraced the fact that CSS is best leveraged externally (well, aside from fringe cases like inline styles for HTML emails and for one-off cases where a dynamic system ‚Äì PHP, CF, JSP, ASP, etc ‚Äì needs to inject a ‘temporal’ change into an HTML page or resources), as it allows you to work on one asset ‚Äì a single CSS file or combination of them ‚Äì and then see those changes propagated out to all of the content that subscribe to them. Well-formed markup can be completely face-lifted via CSS without touching much if any of the content structure. That’s a HUGE productivity boost. Sure, you can do sitewide greps to yank out blocks of code or swap it and achieve the same results, but having done that for years with large sites (i.e. macromedia.com and adobe.com, as well as the sites I worked on beforehand) it’s also incredibly fraught with issues, caveats and potential snafus. Mess something up that way, and you’ve compounded the problem to the nth degree, in fact.

As HTML-based experiences become more dynamic, and Javascript finally reaches the mature potential that DHTML hinted at years ago, it will ‚Äì at least in my opinion ‚Äì become as critical to separate the JS layer from our HTML content layer as it was to do so with CSS years ago. After all, that’s what the promise of HTML selectors were from the get-go! We’ve heard from a ton of Dreamweaver users over the last cycle that as they begin designing experiences that are more dynamic in nature, or take part in larger Ajaxian workflows with true development teams, that the inline event handler model in JS we’ve become accustomed to falls flat quickly and does not allow the tasks to be adequately separated.

That’s why I do feel it’s a very strong best practice, as well as the intention of the standards to begin with, to at least try to externalize Javascript whenever and wherever possible- particularly in areas of markup that are global for your site. Sure, inline styles and event handlers/JS can still be used ‚Äì and are no less valid – but if you can simplify and centralize your Javascript code the way we already do as second nature with CSS, it seems to benefit everyone, at least to me. Problem is, we’re more familiar with the design woes of inline CSS than the behavioral woes of inline JS, so the benefits aren’t as immediately apparent- not to mention the fact that no web authoring tool ‚Äì including our own ‚Äì handles this workflow adequately today. ;-)

Next, we have a viewpoint from Dave McFarland. Dave is the Dreamweaver editor of MX Developer’s Journal and author of Dreamweaver MX: The Missing Manual. Find out about his latest projects at www.sawmac.com. Dave has been designing web sites since 1995. He’s a professional web designer and educator who has worked with the University of California at Berkeley, Intuit, and Macworld magazine among others. He is a frequent speaker at web-related conferences and teaches web design and development at Portland State University. He is a Macromedia Certified instructor and a member of the Dreamweaver Advisory Council.

Unobtrusive JS isn’t for the developer’s benefit–it’s for the end users so that even those without Javascript enabled can access content on your site–this includes search engines as well. If a navigation bar is entirely generated from Javascript, for example, search engines and non-javascript enabled browsers will not be able to access your site.

But, even for developers, unobtrusive JS needn’t be a pain. For example, a Javascript library like jQuery, Prototype or Spry, actually makes assigning event handlers easier than using inline event handlers. Here’s an example with jQuery:

$(document).ready(function() {
$(‘#gallery img’).each(function() {
  var imgFile = $(this).attr(‘src’);
  console.log(imgFile);
  var preloadImage = new Image();
  preloadImage.src = imgFile.replace(‘.’,'_h.’);
  $(this).hover(
    function() {
      $(this).attr(‘src’, preloadImage.src);
    },
    function () {
      $(this).attr(‘src’, imgFile);
    }
  );
});
});

This code preloads any number of rollover images and assigns both mouseover and mouseout event listeners to already existing images on the page. It works for any number of images–if you had to assign inline onmouseover and onmouseout event handlers to each image in the HTML, you’d be keeping yourself pretty busy.

Next, we’ll hear from Nick Crossland. Nick’s been creating stuff for the web for over 10 years, and currently works at Rocket, a web design agency in Sheffield, UK, working on sites for clients ranging from one-man-bands to major public sector projects. I’ve a passion for making things as simple, friendly, usable and accessible as possible. Nick’s digital persona also hangs out at his personal site, nickcrossland.co.uk.

Why is unobstrusive JS a good idea?

It means you don’t have to have an elephant’s memory
Every time you (or someone else working on the site, or a user via Contribute or a CMS) adds in one of the elements that needs the trigger on it, they have to also remember to add the JS trigger to the tag. Are you happy trusting it to your memory? Or the user of the CMS? Or the skills of someone without JS skills as good as yours to put in the code correctly? One error on the page is going to break all the JS on it – not a good move!

It makes naughty scripts play nicely with each other
Imagine you are building a snazzy gallery page of your site, and whenever the user rolls over an image, it should display a tooltip and also a preview of the larger version. Any HTML tag can only have one JS trigger for each event, so you then have to start combining the code from both triggers into one event attribute or function – losing the separation of different bits of functionality, and making it harder to read, maintain and update. Modern JS libraries such as Jquery and Prototype make it really easy to attach multiple events to any trigger, while maintaining that separation.

It degrades your mind
We all know that Javascript reliant applications should also degrade gracefully, so those without JS enabled can still use the site in a sensible way. Seeing the raw HTML without inline javascript is a great mental reminder that the thing still has to work when the JS is stripped away ‚Äì it’s not foolproof, but is a gentle prod that stops you being lulled into assuming the JS will always be there and working.

Otherwise, it’s just getting it wrong
All pedants of the English language know that confusing your verbs and nouns is not only inelegant, but technically incorrect (as anyone who has ever googled someone they want to room with knows). Doing it with the language of web development is no different ‚Äì it will still get the message across, but in a way which will annoy the vocal minority of people (myself included) who like things done “properly”.

Finally, I’ll offer my opinion. I’m honored that Dave and Scott offered to be a part of this experiment. Like my colleagues, I’ve been in software and web development since the early ’90′s. I run a small development studio in Dallas and focus primarily on developing custom systems for small business. I am active in the web development community and, like Dave, participate in the Dreamweaver Advisory Council.

I’ll admit that the first time I heard of Unobtrusive Javascript, I didn’t quite grok the benefit. It smacked of something evangelized by the Propellerheaded Bini-istas that should be done just because it could be done.

I run a small shop and often develop web systems with one or two other programmers at most. Rarely have we needed to work within a large team so I have the luxury of developing in an expedient and efficient way, so my perceptions on this topic are colored with this bias.

I’ve given Unobtrusive Javascript a fair shake. My opinion is that it has some utility. The techniques, for example, prove very useful for a feature that is site-wide such as custom skinned buttons or common navigation features. I by no means argue that UJS shouldn’t be used. I simply believe that a site shouldn’t be considered poorly written or deficient in some way if every JS function isn’t abstracted.

Many argue that separating functionality from content is just as important as separating presentation from content. After all, the benefits of abstracting CSS into common stylesheets has been proven over and over again.

I disagree. By definition, the way the site looks must be consistent from page to page. Therefore, CSS common throughout a site is a must. But the same is not true for JS-derived functionality (for the most part).

Think about your typical use of inline JS. The vast majority of the time, you are triggering some function based on the users interaction with a single object. A button is the best example. If this button appears on every page on the site, sure, abstract it and externalize it. Your user will thank you, and making changes to the functionality is much easier. However, a much more likely scenario is that a single object on a page triggers some unique event. While the code that performs said function certainly should be externalized for optimization and efficiency, going the extra step of removing all of the triggers from the button actually swings the pendulum of efficiency the other way.

For one, it leaves an orphaned button by all appearances. When you open the code later on, you have to dig through external code just to find out what a button does and how it is triggered. For another, the time to implement the external code–assuming you don’t have a tool that automagicallly does this for you–takes longer.

So, in the end, I find that the happy medium is externalizing the functions and classes that are triggered while leaving the inline triggers intact. I’m sure the MVC purists would scoff at this, but then, I’ll be done with my project a lot more quickly than they will.

My goal with this article is to provide different perspectives on a controversial topic. There is no right or wrong answer. Ultimately, your use of UJS must fit into your individual and team workflow. Feel free to weigh in yourself by commenting below.

Sphere: Related Content