classical geek

The Coders’ Pyramid

It’s a truism to say that there’s a food chain in software development, whereby a few highly-skilled developers at the level above create components and frameworks for use by the larger, less-skilled mases in the layer below. A small handful build operating systems, on top of which are built virtual machines and interpreters. On top of these are built frameworks and components that are glued together by those in the lowest layer, creating desktop apps and web applications. (And by ‘lowest’ I don’t mean any value judgement. These people may possess business knowledge, desighn skills or whatever that make the actual coding a less central part of their role than, say, the engineers fine-tuning a VM or writing a filesystem driver.

It’s a truism, so I’m not going to talk about it anymore.

Rather, the interesting thing to me is the gap between any two layers. A developer at any layer in the coders’ pyramid might be doing a role that can be readily described by that layer for, say, 90% of the time. But now and then, they’ll need to go up and down a layer.

I’ll take myself as an example - I build J2EE/Ajax software for a living. Mostly, I’m consuming other people’s frameworks, such as Struts, Spring, JFreeChart and Hibernate, and the developers of those frameworks sit in the layer above me. Above them are the people who write the J2EE app servers, and above them the people who write the JVM. In the layer below are the business analysts and tech sales people who customise my solutions for customers. Sometimes I have to go down a layer, and bend my brain into really understanding the business domain that I code to. And sometimes I go up a layer or two, to poke around in the code for a third-party library - or even the app server - and possibly submit a trivial patch or two.

In the case of java libraries, going up a layer is pretty straightforward, helped by the fact that a lot of the libraries that I use are open source, and are written in the same language that I routinely use, Java. If they’re well-factored and well-documented, then so much the better.

I can contrast that with experiences several years ago writing classic ASP. The built-in scripting environment didn’t give away too much, and in order to do any general-purpose sort of programming, such as opening sockets or spawning new threads, it was necessary to bail out of VBScript and write an ActiveX component (or, more often, find one that already did what you wanted). Once written, it had to be installed on the sever, which could be problematic in certain hosting solutions. Most decent ActiveX components were written in C++, and the move from VBScript to C++ was pretty hairy.

This isn’t an anti-MS rant. As far as I know, that issue is old hat, and ASP.Net gives the developer everything they want in terms of general programming capabilities within C# or VB.Net. And on the other side, a java developer hits that shiny featureless wall when they step outside the comfort of the JVM to perform some native code, and have to either spawn a process or write JNI code to get traction.

OK, onto the Ajax bit now. What eventually got me thinking about this again was the increasing complexity of JavaScript code now that Ajax is here. Traditionally, JavaScript has only occupied a single layer of the pyramid, with coders hacking together whatever solution they need and moving swiftly back to the server-side language of their choice. Nowadays,though, the number of Ajax frameworks has been increasing dramatically, so we’ve got a two-tier JavaScript ecosystem now. We can ask the question, then, of how easy it is for the casual user of an Ajax toolkit to step up a layer to look inside the toolkit and do a bit of figuring out.

Let’s take Thomas Fuch’s Scriptaculous library as an example, in particular the Effects library. Again, I’m picking on this example because I’ve used the code a lot myself, and I like it. I’m not singling out Scriptaculous for any criticism, just using it to illustrate a general point. On we go, then.

Creating an Effect is laudably trivial:

new Effect.Scale('myDOMElement',200);

or, with a little more customisation thrown in:

new Effect.Scale(
'myDOMElement',200,
{ scaleX: false; scaleFromCenter: true }
);

and that’s it! Your DOM element will do duinky animated stuff before your eyes. Now, let’s have a look at the implementation of that effect:

Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
initialize: function(element, percent) {
this.element = $(element)
var options = Object.extend({
scaleX: true,
scaleY: true,
scaleContent: true,
scaleFromCenter: false,
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
scaleFrom: 100.0
}, arguments[2] || {});

…more code, omitted for brevity…
});

Suddenly, we’re in fairly dense JavaScript code, making use of a number of expert features. (I should point out that my blog software is futzing up the indentation here, making it a bit harder going than it could be.) Look at the declaration of var options, for example. Object.extend is defined by the Prototype library, as a way of passing a parent classes’ (or rather parent prototype’s) members to a child. A set of default arguments follow, which comprise the parent settings in this case.

The child is defined in a very concise fashion as arguments[2] || {}. That is, if we have passed in an array of customization arguments (see our second invocation of Effect.Scale above), those arguments will be used to overwrite the defaults provided as the parent. For any values not overridden,the default will be used. And if no argument is passed, then our defaults will be overridden by an empty associative array {}, returning the unchanged set of defaults. Once it’s dissected, it makes sense, but figuring out that much from scratch requires quite a bit of deep JavaScript knowledge:

  • the logical OR-ing of arguments[2] works because Functions can take optional arguments, which will evaluate to false if omitted.
  • JavaScript objects and associative arrays are really the same thing, allowing us to use Object.extend() on what looks like a plain old hashed array rather than an object.

Arguably, if somebody can’t figure out that much, then they shouldn’t be writing JavaScript anyway, but this is folk knowledge, not common sense. There are plenty of competent coders who will have the odd bit of JavaScript thrown at them out of the blue from time to time. They’re the people that I have in mind here.

In the interest of fairness, let me point out that Thomas has provided an admirable middle ground for those wantng to tweak their Effects a little, by allowing them to be composed. Here’s the code for the composed ‘Puff’ that ships with Scriptaculous, combining a scaling and a fade-in, after which the element vanishes. The syntax is still a bit thick in places, but shouldn’t be beyond the grasp of most coders to customize a bit to their own purposes.

Effect.Puff = function(element) {
return new Effect.Parallel(
[ new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true }),
new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0 } ) ],
{ duration: 1.0,
afterUpdate: function(effect)
{ effect.effects[0].element.style.position = 'absolute'; },
afterFinish: function(effect)
{ Element.hide(effect.effects[0].element); }
}
);
}

So, going back to the bigger picture, here’s something for the authors of JavaScript libraries to consider. How much of a gap are you creating between using your library, and being able to modify or enhance it? Does such a gap present a barrier to its uptake? Should good code be there to be read as well as executed?

1 Comment

  1. […] esign, Java, JavaEE, Javascript, ObjectOriented, Scriptaculous, Software Dave Crane looks into some Scriptaculous code. The main point is that Scriptaculous is […]

    Pingback by Software As She’s Developed - Reading Open-Source Code — September 8, 2005 @ 3:54 pm

RSS feed for comments on this post. TrackBack URI

Sorry, the comment form is closed at this time.

Powered by WordPress, Supported by SaveOnRefinance.com