Be Library Agnostic

One of the slides in my presentation at Webvisions last year was titled "Avoid Library Calls". The idea behind this was to try and build your code in a way that it didn't need to be tied so deeply to one particular library.

Here's the example I used:

function makeBlack(elementname){
  $(elementname).style.color = '#000';
}

function makeBlack(element){
  element.style.color = '#000';
}

In both cases, I have to make the call to the makeBlack function but in the second example, I've already received the actual element and can perform my magic on it directly; I'm not tied to any particular library.

Moving Forward

With the recent announcements of Jack Slocum's Ext moving to support jQuery and jQuery supporting OpenAjax, I feel like the JavaScript community is slowly moving towards that ideal.

When using a JavaScript library, there are commonly three tiers to an action:

  1. Core code
  2. The Bridge
  3. Library

The core code is the whole purpose of whatever you're trying to accomplish. It's the photo gallery, it's the star ratings, it's what you're getting paid to do.

The library is the reusable components for handling DOM retrieval, event handling and so on. This might be jQuery, Prototype or you own custom home-brewed solution. Either way, this is the base that you pop into every project you start.

All hands to the Bridge

The bridge is the component that most people don't bother with. Most would take the core code and tie it in directly with one's library of choice. Thing is, creating a bridge via JavaScript can actually be quite straightforward.

Take a look at Lightbox 2.0 as an example. Looking through the code, only a small portion of it is actually reliant on library-specific functionality like:

Element.show('caption');
Element.setInnerHTML( 'caption', imageArray[activeImage][1]);

This type of functionality is found in more than one library and minimizing ones footprint within a library gives you the flexibility to quickly and easy move to another library. For example, wouldn't Lightbox be handy for those who use jQuery[1] or YUI?

JavaScript makes implementing a bridge quite easy because it's easy enough for us to override and overload functions from other libraries without a large footprint. For example, you might like to use $ to retrieve elements. Sure, jQuery and Prototype have $ functions but what about YUI? Sure thing, just map $ to YAHOO.util.Dom.get and just like that, none of your core code has to change.

Wasteful?

For some, adding a bridge component to their applications on top of a hefty JavaScript library seems wasteful but if you're developing something to be repackaged and reused (like Ext or Lightbox) then the additional footprint can be minimal. Ext's jQuery bridge, for example is only 6k. Considering the entire Ext library comes in at 373k, that's less than a 2% increase in size to maintain library agnosticism.

For those not having to rely on redistribution of code, minimizing your direct ties into a library may save you time and effort down the road when it comes to refactoring, either to switch libraries, upgrade to a new version that may have API changes, or reusing the component within other internal projects.

I'm definitely pleased to see jQuery and Ext moving in this direction and I suspect we'll see more of this in the future.

[1] Yes, I know about Thickbox, I'm just saying.

Published February 27, 2007
Categorized as JavaScript
Short URL: https://snook.ca/s/772

Conversation

7 Comments · RSS feed
Tobie Langel said on February 28, 2007

Hi Snook,

Definitely an interesting perspective you share here.

I would however tend to think that this is easier to do with libraries that are more functional than object oriented.

As soon as you start relying on methods of an extended prototype, this gets arguably more difficult to achieve without getting pretty close to defeating the purpose of using a library or framework in the first place.

Bramus! said on February 28, 2007

Very interesting perspective and writeup!

@ Tobie: about "methods of an extended prototype". They're handy, but totally mix up everything.

In my opinion they should only be used for adding functionality of a higher JS version to an older version (cfr. Array prototype extension as Dustin did).

All other extensions should - again my opinion - be placed in their own class: viz. don't extend the prototype of elements to have an addClassName function, but place them in a separate class (just choosing a name here) Element so that you'll end up with Element.addClassName(the_element, the_classname) (the prototype library supports both).

wbr,
B!

Jonathan Snook said on February 28, 2007

@Tobie: that is very true. There's certainly a limit to how effective this can be depending on what it is you're trying to accomplish. Ultimately, JavaScript is a functional language so these issues can be easily worked around; hence the reason I think bridges are easier to build in JS.

For straightforward stuff like event handling, DOM retrieval and simple DOM manipulation (possibly including animation), a bridge would be quite practical. This would account for the 80% of cases most people run into in development. The extra 20% may not be practical.

Ahsan said on February 28, 2007

Very interesting and new stuff for me.

I am just getting into the use of JS libraries, and have been wondering a lot about what to look for in a JS library. I was also very concerned about the idea of committing to a library, and later regretting it.

But, thanks to your article, now I finally see the solution. If my code is written with a bridge like layer in the middle, switching libraries will not be as difficult of a task as I thought.

Hopefully with a little more experience, I will be able to write JS in this technique.

Thanks :)

Andy Kant said on February 28, 2007

Bridges are very useful and is usually how I deal with changing frameworks. As for changing API's/interfaces...I wrote a method that allows me to attach preprocessors and postprocessors to any function which is pretty useful. Its great for rearranging arguments as well as normalizing or validating data. If an API changes though, the bigger issue is poor design and management. You should always leave legacy interfaces in your library (the only exception being a major release for a framework).

Tobie Langel said on February 28, 2007

@ Bramus!:

In my opinion they should only be used for adding functionality of a higher JS version to an older version

Well, I suppose that it is necessary if you want to be library agnostic.

I guess I'm ready to pay the price of being tied to a library in order to be able to write short and explicit code:

' border-top-width   '.strip().camelize();
// -> 'borderTopWidth'

rather than the bulkier:

String.camelize(String.strip(' border-top-width   '));
// -> 'borderTopWidth'
Michiel van der Blonk said on July 13, 2007

Instead of having bridges scattered all over the city to connect the neighbourhoods, it seems a lot easier to make one defined spec that all libraries should abide to. This spec, maybe call it AJAL (a javascript api for libraries, LOL) can then be defined for the large part of functionality that is common to all or most. We could think of DOM, Drag n Drop, CSS, Windows, Events, Animation, etc.

Then Libraries could comply to a version of the standard. Basically nothing new that hasn't already been done for HTML, CSS, DOM.

While a library is not yet compliant as-is it could start offering a javascript bridge to the standard.

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.