Let’s talk about JavaScript libraries
JavaScript’s got a bad rap; it’s the language everybody loves to hate, and the one language which, more than any other in the modern web developer’s toolbox, people will go to insane lengths to avoid writing directly (witness Google Web Toolkit, JavaScript “helpers” in server-side frameworks, etc.). Which isn’t fair, really, because (as I’ve said many a time) most people don’t actually hate JavaScript the language; they hate the buggy and inconsistent implementations of JavaScript in major web browsers and, to a larger extent, the buggy and inconsistent implementations of the DOM in major browsers.
Now, for about as long as there’s been JavaScript there have been reusable libararies for it floating around; in the old days they were called “DHTML libraries”, now they’re usually called “JavaScript libraries” or (shudder) “AJAX libraries”. In general, they make writing JavaScript a whole lot easier. No longer do you have to remember the fourteen different ways to add or remove an event listener. No longer do you have to know where each browser stores its XMLHttpRequest
object and which order you have to use to compatibly look for them. No longer do you have to hack around Safari’s chipmunks-on-crack animation speed. Someone else has already run into that, figured it out and made the code available; hallelujah!
But… there’s always been this sense that use of a library is to be frowned upon; that if you use a library you’re somehow not a “real JavaScript programmer”. And some fairly big names in the JavaScript world have gone on record actively discouraging the use of libraries. Apparently you should only use a library if you know enough about JavaScript and its various implementations to write the library yourself, in which case you don’t need the library. Anyone who doesn’t have that level of knowledge is like a child playing with a gun, they tell us (though Stuart Langridge has retreated somewhat from that extreme position, and seems to be ever-so-slowly dragging Peter-Paul Koch along with him).
So let’s look at the problem (or lack thereof) of modern JavaScript libraries, and see if we can’t come to some useful conclusions. Like my previous entries on server-side web frameworks, this will be a series; in this installment we’ll look at common objections to library use in JavaScript, and some responses to those objections.
The field of battle
A number of objections to the various popular JS libraries kicking around today are rooted in a lack of good documentation, a problem which afflicts far more things in the software world than JavaScript libraries. I’m going to hold off on that one for now, because it’s really an objection to specific libraries, not to the concept of libraries in general. Setting that one aside, three primary concerns seem to surface over and over again:
- Some programmers are control freaks and would rather have their Internet connections amputated than use a line of code they didn’t write themselves.
- Using a library will unnecessarily “bloat” your code, either by increasing the amount of JS users have to download, or by slowing down your code with the overhead of using the library.
- If you don’t have a thorough understanding of how the library works (and, therefore, a thorough understanding of JavaScript and browser quirks), you won’t be able to use it effectively and may end up shooting yourself in the foot.
Let’s look at each one of these in turn.
NCBM (Not Coded By Me)
The control-freak problem is tough for me to understand, because I don’t suffer from it. I’m a self-taught programmer, and I learned very early on that good libraries are a programmer’s best friend; they save you having to solve a problem that’s already solved, and reading the code can often be a useful learning experience for non-experts. The control-freak viewpoint of “I don’t trust anyone else’s code” runs directly counter to that, and makes me feel a bit uneasy. Pretty much every programmer has to trust somebody else’s code at some point:
- C and C++ programmers have to trust the people who provide their compiler and their libc and/or STL.
- Java programmers have to trust the people who provide their JVM and class library, and C# programmers have to trust the people who provide their CLR and .NET libraries.
- Programmers who write Python, Ruby, Perl, PHP or other interpreted languages have to trust the people who provide the inerpreter.
- Everybody listed above has to trust an operating system vendor.
And web developers have to — at least to some extent — trust whoever wrote the web browsers. No matter who you are and what type of programming you do, unless you wrote the full stack — OS kernel, libraries, compilers, runtimes and interpreters — at some point you’re trusting somebody else’s code. So if you’re having control issues, get over them right this minute and stop thinking “eww, other people’s code”, because that’s not productive. The right thing to think when you see a library is not “I don’t want to use third-party code”, it’s “how good is this third-party code and how well does it solve my problems?” Sometime in the next couple of days I’ll try to tackle the answer to that question for JavaScript libraries.
The library that ate Chicago
Library “bloat” is a tricky criticism to deal with, because it’s really about two separate issues: one is the amount of code your users end up downloading, and the other is the amount of time it will take for that code to execute in a web browser.
When it comes to the number of bytes sent down the wire, using a library does introduce some measure of “bloat”; you’re probably not using everything the library defines, so no matter what you’re including more code than you would have otherwise.
But most of the good JavaScript libraries help you work around this: some do their best to stay tiny, confining themselves to a smaller set of functionality in order to reduce the amount of code, and others are large when considered in total, but are logically broken down into modules so you can have finer-grained control over how much of the library you’ll actually use. Combined with size-reduction tricks — there are JS-specific compressors which can strip comments and unneeded whitespace (and some advanced ones which can do even niftier tricks), and you can zip the file(s) server-side before you put any bits on the wire — these approaches let you keep your code to a manageable size.
“Bloat” in the sense of code that’s slow because of overhead introduced by the library is another matter, and is usually more of a tradeoff than anything else. For example, lots of libraries provide methods for using CSS selectors or XPath queries to specify a set of elements to retrieve from a document, and these methods have, historically, been relatively slow (though they’ve improved a bit with time). Whether to use these methods, then, comes down to weighing two options against each other:
-
If you don’t use them, you’re stuck with the DOM API, which is cumbersome and ugly to use; you end up with code that looks like a train wreck, mashing together repeated calls to
getElementById
,getElementsByTagName
, iterations overchildNodes
and endless regular-expression tests againstclassName
. It’s not uncommon to need a way to fetch, say, all theli
elements with a given class name inside aul
which is the third child of the fourthdiv
inside a container with a particularid
, and the DOM API is horrifically bad at expressing that sort of thing, so you end up writing lots of one-off slabs of code which fetch elements according to specific parameters. - If you do use them, you get the benefits of clean, concise syntax — CSS selectors and XPath queries are designed from the ground up for quickly expressing conditions which describe an element or set of elements — and of generality: when the HTML changes, you just change the selector or query, instead of rewriting a huge mishmash of DOM method calls. But now you’re incurring the overhead of a system which can parse CSS selectors or XPath queries, and which can’t optimize the eventual lookups as much as a specific, one-off hack.
Given that computers are continually growing faster and that there are reliable ways to make expensive bits of code execute immediately while a user is still scanning the page (before they can interact with it, they have to see what options they have for interaction), it’s not hard to see why a lot of people choose to use the fancy methods with the clean syntax. But at the same time, nobody’s forcing anyone to use them, and performance-critical bits of code can always be rewritten using specific one-off collections of DOM methods.
The knowledge gap
This is probably the hardest objection to deal with, for a couple of reasons. First of all, it comes off as an awfully snobbish thing to say: “oh, don’t try to play with the grown-ups’ toys, you’re not ready for them yet.” And, in a way, it is an awfully snobbish thing to say; it’s as if the experienced JavaScript programmers are all turning their noses up and sneering at the poor peasants who can’t recite IE’s proprietary event-handling system from memory. This is a serious issue not because it scares people away from JavaScript libraries, but because it scares them away from learning about JavaScript; if they see too much condescension from the “experts”, new programmers won’t have much incentive to learn more than the bare minimum they need to deal with the task of the day.
But there is some practicality in the snobbishness; if you don’t have a certain familiarity with JavaScript and with browser quirks, you could be in for a lot of trouble:
- You might not be able to figure out how to use a particular library.
- If you can figure out how to use a library, you still might not be getting the most out of it because you don’t know what options it really gives you.
- The library you end up using might have bugs which you don’t understand and can’t fix.
- You might inadvertently use it in an unsafe way and end up with cross-site scripting bugs or other security problems.
None of this, however, points to a problem with the idea of libraries; every programming language which allows the use of libraries or modules potentially has these problems, and they all go back to a lack of knowledge. The solution, then, is not for knowledgeable JavaScript programmers to issue edicts of doom and try to frighten novices; the solution — as Stuart and PPK have pointed out — is for those knowledgeable programmers to help people learn enough to make good choices about library use, and to use libraries and the language safely and effectively.
But that makes this the toughest problem to deal with, because closing the knowledge gap an uphill battle. Worse, it’s uphill from both sides: expert JavaScript programmers aren’t all that common, so the few who are out there have a lot of demands on their time which can keep them from being as helpful as they’d like. And JavaScript is such a universally loathed language that people who don’t know it will go to unbelievable lengths to avoid ever learning it. The sort of friendly, well-informed evangelism JavaScript needs is in short supply, and likely to remain so for the foreseeable future, though I’ve got some thoughts on that which I’ll get to a little later on in this series.
Let’s break for the day
I think that’s probably enough for a first foray into discussing JavaScript libraries; we’ve only scratched the surface, but already there’s a lot to think about, so I’ll stop here and let it all digest for a while. Check back in a few days for the next entry in the series, which will cover some ideas on how to evaluate a JavaScript library and decide which one, if any, you want to use.