Monday, 23 July 2012

Javascript - so unobtrusive I can't even find it

Ok, so, what's the problem with obtrusive javascript?

Near as I can tell: it's a bit messy having all your js intertwingled with the html. Much like the once-dreaded embedded font tags - for which stylesheets were a wonderful invention. They pulled everything out of the way and kept them in one place , which cleaned things up a lot.

Enter: unobtrusive Javascript. Your JS is tucked away neatly, and placed onto your active DOM objects via id-tags et al - just like your stylesheet.

What are the down sides?

Well - lets say there's some magic JS doing something with the Foo element on your page... only there's a bug in it and it needs fixing ASAP. But all I know is which part of the page is being updated - I have no idea where the JS is located. The KS-functionality appears like magic from.... somewhere.

Lets complicate things (like real life) and say I'm new to the project, and the previous developer quit and is now living on a beach somewhere in a non-extradition country... so I can't ask them.

How do I actually *find* the JS that is unobtrusively messing with my html element?

It's ok if there's just one JS file that does a few things, or if you have a JS file per HTML page or some other sensible way of finding out which JS belongs on what page... but if you're coming onto the typical legacy project, you've got dozens of JS files with uncommented JS code for adding, removing, showing, hiding, dragging, dropping elements willy nilly - some of which are no longer used and who have useful, non-unique names like "move_stuff" or "display_items".

Sure, I can grep across the project for the ID of the html-element in question... unless the JS is operating on it via the DOM (eg every second child element of a td from a table that's inside the third div from the left...). But it's a little awkward.

There's also one other problem. Let's say I *don't* happen to know there's any JS operating on this element, and I update the html without even realising there's some accompanying JS to update (remember, I'm new to the team, and the former developer wasn't much for commenting).

Now the html and JS are out of synch. The JS is almost certainly broken, because I've just moved that html element into the second div from the left and nested it inside another table... and I will never know it was supposed to "display_items" then "move_stuff"... until Joe Random User suddenly notices that he can't submit the end-of-year accounting because the submit button no longer magically appears when he's finished filling out and validating the form (or whatever).

Clearly there are some benefits of the JS being tucked away out of sight (it looks prettier, which makes the html easier to maintain) but there are also clearly some disadvantages (it makes the JS itself difficult to maintain - two separate files mean a synchronisation-problem).

So, what's the solution?

As ever in design for computers, there's a balance/tradeoff involved, and your decision will probably involve a sightly different balance to what we do.

Personally, I like keeping the JS alongside the HTML it operates on. Sure, don't have it entangled in the html, but you *can* have your JS near the html that it relates to and still have it take into account the aspects of unobtrusive JS. ie the JS still adds to your HTML elements by using ids and DOM-paths... but the actual JS is either in the same template as the HTML (at top of bottom of the file), or is in a partial that's included into that template - so you always know it's there.

I'm sure it's far from the "perfect" solution... but it works for me, and makes it less likely that I suffer from the two problems outlined above, ie that I:

  1. can't find related javascript
  2. don't actually realise there *is* related javascript to keep in synch

What solutions do you use?


boon kiat han said...

this seems to be a 'taste' issue,

there will also be the counter-arguments by those who prefer their scripts to be near to each other and often, selector libs use the CSS syntax which makes it rather easy to mentally map the listeners back to the document elements.

In production, you might want to concatenate it into a single file or defer certain scripts.

Scattering scripts probably only yields marginal benefits for some trivial onclicks.

If you never need to work with others or the application remains dirt simple... plausible...

Taryn said...

Oh absolutely. I can see every benefit of tucking the javascript away (better caching/minifying DRY etc).

But it definitely introduces the problem of de-coupling the two - leading to the problems I mentioned. Especially when there are one-page-specific scripts that do non-standard things.

I mean I have no problem with tucked-away code for obvious, common things such as (for example) tables with sortable columns. Those are common enough that looking at more than one will give you a good idea of what you should do and not do to the html. Form-field validations are also a good example - there are pre-written common libraries for that, and it's then easy to spot.

But if I just chance across a random partial template (that somebody else wrote way back in the mists of time) that has a bunch of ids and CSS-tags... how do I tell whether or not there is javascript attached to those? How do I tell that I'm not breaking it? :(

webstandardcss said...

With CSS I can right click an element and use Chrome to inspect element.

This lets me see if and where the CSS is located that acts on my HTML element.

I think we need something like this for Javascript.

Can you tell me how this is possible?

Taryn said...

Neat idea!

I use firebug (firefox plugin) which does a similar thing with finding where CSS is coming from.

It'd be great if it did the same thing with javascript.

Right now it doesn't do it quite the same way as with CSS - you have to go find the javascript yourself and set breakpoints etc.

Of course it doesn't help you with the "I didn't know there was any javascript to go find" problem - but something like that would help in finding known-but-magic javascript.