Cujo 1.4 review


D

David Mark

Cujo 1.4

(For those wondering, Cujo was a big, sick dog that ought to have been
put down.)

The poor, deluded souls trapped in the hell that is Dojo to date keep
promising a squeakquel in 2011, or 2012 or some far off time.
Apparently, it will be the one that finally makes the world stop calling
for its demise (I'm not the only one who scoffs at this one).
Personally, I don't see how years of piling garbage on top of garbage is
going to render gold in the future.

As I was once asked to clean this mess up (by its owners) and
subsequently had the "privilege" of interacting with the contributors on
some impossible-to-find mailing list, I think I can say without fear of
contradiction that they are dreaming.

One of the first things I did was axe the "XD loader" and all
synchronous XHR in one swipe. The loader thing was ridiculous in that
it made you develop and test code that will ultimately be run through a
complicated wringer at deployment (resulting in something very different
from what was tested). And synchronous XHR; well, what can you say
about that? Some people tried to tell them back in 2007, but they
didn't seem to understand the complaints (preferring to call the
complainers "trolls"). Yes, 2007. I didn't even glance at the thing
until 2009, so they had been asleep at the switch for years on the
synchronicity issue.

http://ajaxian.com/archives/apple-store-hits-the-dojo

Yeah, they should have hit them harder. :)

In short, the change was a watershed moment for the project and a
handful of contributors initially praised it due to the vast improvement
in loading time (without freezing the browser) and the ability to do XD
loading without the aforementioned wringer fouling everything up.
Dumped ten tons of browser sniffing after that and then dealt with the
unit tests, which had been fairly well screwed up (as one might imagine
after such dramatic changes). Got them all to pass and things were
looking promising (as I mentioned a few times last summer). But then
the tail end of the group shuffled into the picture and started up with
the usual cargo cult BS (e.g. can't check in even the tiniest patch
without ten years of "review" by the people who screwed things up in the
first place). They were ultra-paranoid too. Couldn't stand that their
warts were being exposed in "public" (quotes indicate it was a developer
list that nobody could find and wouldn't read if they did). Before
long, it was "aw, you don't know everything--we're smart too" and not
long after I bid them farewell (and go to hell).

I did notice that about six months later, stumbling onto a commit report
in some Google results, that they were frantically pawing through the
new branch (that they had previously refused to read, citing time
constraints) to try to figure out what I did. I told them to leave _my_
code alone (and wouldn't you know, they actually deleted the branch
without even the tiniest inclination of what I might do if they didn't).
That I did not expect (even from them). But, of course, they've got
it stashed somewhere and I am sure they will try to use it as a cheat
sheet for their "new" version. Could raise some issues if I see any of
my stuff show up though. :)

So the browser sniffing is surely still in place (the code at every
level is hopelessly tangled up with UA string inferences). And I know
they didn't fix their loader. But those were just the two biggest
problems. There were literally thousands of instances of ill-advised JS
(e.g. broken global eval, tons of isArray calls, etc.) As for browser
scripting missteps, they were everywhere. Augmented host objects are a
way of life for them. Memory leaks? You bet, as they constantly
reference host objects with properties of Object objects (the first two
links in a chain, just waiting for one more to form a circle). Yeah, I
tried to explain that one too. It seemed to make them angry (again, the
paranoia that their "fans" could be reading). Quotes indicate that,
near as I could tell, the only fans they've got are people who have
wasted lots of time working on the thing.

So there are hundreds of files in their ZIP, many of which are put
together the same way on every refresh (using their loader of course),
making testing a sluggish nightmare. When something would go wrong with
one of them during load, instead of getting the exception and
accompanying stack trace in the console, you get a "friendly" message
(something like "Module xyz failed to load" (yes, I got rid of that
nonsense too, else I'd have never finished the renovations). But
anyway, I will just review the lowest-level file in the core
(bootstrap.js). As it goes, so does Dojo (and you should know where it
is going without reading any further).

Without further ado, here is the lynch-pin of this advanced "cutting
edge" framework (roughly five years into its existence). Please hold
the boos (and tomatoes) until the end of the review. :)

[snip long-winded exposition about configuration variables]

//>>excludeStart("webkitMobile", kwArgs.webkitMobile);
(function(){
//>>excludeEnd("webkitMobile");

Well, that's not a promising start. The ridiculous "webkitmobile"
nonsense was something else I dumped. Here he have a one-off function
removed so that in _some_ browsers (per the UA string of course) the
following code will run in the global context. Could pretty much end
the review right there. I mean, in what universe does that make sense? :(

[snip console-related BS]

//TODOC: HOW TO DOC THIS?

Please stop shouting (especially when there is nothing to say). :)

// dojo is the root variable of (almost all) our public symbols -- make
sure it is defined.

That has no real meaning. It's pretty poor grammar too. Polished this
effort is not (despite years in the making and a cast of thousands).

if(typeof dojo == "undefined"){
dojo = {
_scopeName: "dojo",
_scopePrefix: "",
_scopePrefixArgs: "",
_scopeSuffix: "",
_scopeMap: {},
_scopeMapRev: {}
};
}

They love underscores.

var d = dojo;

This was another thing I tore out of hundreds of files. Properties of
the "dojo" variable typically reference tons of host objects, so it
should not be preserved in a closure. The proper solution for saving
the global lookups (and some space on minification) is to create local
references to _methods_ of this object, not the object itself (which I
did in most places). They didn't seem to understand that either
(confirmed now that I see the problem is still there).

//Need placeholders for dijit and dojox for scoping code.

"Scoping code" that has nothing whatsoever to do with scope.

if(typeof dijit == "undefined"){
dijit = {_scopeName: "dijit"};
}

"Dijit" is the umbrella term for a hodgepodge collection of widgets
teetering on top of this stuff. Avoid like the plague.

if(typeof dojox == "undefined"){
dojox = {_scopeName: "dojox"};
}

"DojoX" is basically a garbage dump of contributions deemed not ready
for "prime time" in the Dojo core.

if(!d._scopeArgs){
d._scopeArgs = [dojo, dijit, dojox];
}

/*=====
dojo.global = {
// summary:
// Alias for the global scope
// (e.g. the window object in a browser).
// description:
// Refer to 'dojo.global' rather than referring to window to ensure your
// code runs correctly in contexts other than web browsers (e.g. Rhino
on a server).
}
=====*/
d.global = this;

Does that look like the "global scope" to you? I knew I would have
trouble communicating ideas about JS with people who didn't speak a word
of it.

d.config =/*===== djConfig = =====*/{

I don't understand what those equal signs are about.

isDebug: false,
debugAtAllCosts: false
};

if(typeof djConfig != "undefined"){
for(var opt in djConfig){

Oops, forgot the filter there (and in about a thousand other places).
Running these things through JSLint was a nightmare, but I did finally
get all of the files straightened out. Found lots of typos along the
way, which I expected as they always check in with a self-defeating
!strict directive, which bypasses the lint check. I found such evasive
action to be necessary one out of a hundred check-ins (their lint was
too picky about a few things).

d.config[opt] = djConfig[opt];
}
}

/*=====

There are those damned equal signs again. Something to do with
documentation, perhaps?

// Override locale setting, if specified
dojo.locale = {
// summary: the locale as defined by Dojo (read-only)
};

Looks documentation-related. No wonder the documentation is famously
poor. The locale as "defined" by Dojo?

=====*/
dojo.locale = d.config.locale;

var rev = "$Rev$".match(/\d+/);

/*=====
dojo.version = function(){
// summary:
// Version number of the Dojo Toolkit
// major: Integer
// Major version. If total version is "1.2.0beta1", will be 1
// minor: Integer
// Minor version. If total version is "1.2.0beta1", will be 2
// patch: Integer
// Patch version. If total version is "1.2.0beta1", will be 0
// flag: String
// Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
// revision: Number
// The SVN rev from which dojo was pulled
this.major = 0;
this.minor = 0;
this.patch = 0;
this.flag = "";
this.revision = 0;
}
=====*/
dojo.version = {
major: 1, minor: 4, patch: 0, flag: "dev",
revision: rev ? +rev[0] : NaN,
toString: function(){
with(d.version){

We are only a few hundred lines into the what must be the most critical
lump of JS in this "toolkit" and already a - with - clause. Needless to
say, I yanked that on first sight.

return major + "." + minor + "." + patch + flag + " (" + revision
+ ")"; // String
}
}
}

//>>excludeStart("webkitMobile", kwArgs.webkitMobile);
// Register with the OpenAjax hub
if(typeof OpenAjax != "undefined"){
OpenAjax.hub.registerLibrary(dojo._scopeName,
"http://dojotoolkit.org", d.version.toString());
}
//>>excludeEnd("webkitMobile");

Yeah, I looked at that "OpenAjax" module. It looks to be a complete
waste of time (a common theme).

[snip "mixin" crap]

dojo["eval"] = function(/*String*/ scriptFragment){
// summary:
// A legacy method created for use exclusively by internal Dojo
methods. Do not use
// this method directly, the behavior of this eval will differ from
the normal
// browser eval.
// description:
// Placed in a separate function to minimize size of trapped
// exceptions. Calling eval() directly from some other scope may
// complicate tracebacks on some platforms.
// returns:
// The result of the evaluation. Often `undefined`
return d.global.eval ? d.global.eval(scriptFragment) :
eval(scriptFragment); // Object
}

There it is. I remember when I first tried to explain the illogic of
that to the owners. They started to get really bitchy (like it was my
fault the whole thing perched on logic so loopy it would make VK blush).
I had to remind them that they _asked_ for my advice.

I've asked this here before. Can anyone not see what is wrong with that
picture? Give me any reasonable person who knows nothing about JS or
browser scripting and I can get them to understand the gaping hole in
the logic in ten minutes. Never got anywhere with the contributors
though (who are ostensibly experts at this sort of stuff). In fact, the
first time I brought it up, one of their luminaries scoffed at the
notion that they would rely on eval for anything important. I had to
point out to him that the whole lousy thing relies on that function
(it's what they do with the JS after it is downloaded with synchronous
XHR). Still, it remains today (as does the synchronous XHR).

/*=====
dojo.deprecated = function(behaviour, extra, removal){

It certainly should be. I think that's about enough. Everything that
follows rests atop the above. Trust me in that it doesn't get any
better (and even if it were letter perfect, it would still be shaky due
to its dubious perch). It will be reviewed more thoroughly on
cinsoft.net in the near future. As has been discussed here, the query
module is easily the worst in the business (which is really saying
something) and much of what follows relies on it as well (lots of
dependencies on that module, including the XHR module IIRC). That's the
final punchline: it is broken up into hundreds of "modular" bits, but
basically everything depends on everything else. It's the worst of both
worlds as there is a huge amount of time-wasting overhead involved with
piecing the stuff together on each load during development. I think
that even a non-programmer could pick up on that as well, but not the
Dojo Ninjas.

Somebody should put this thing out of its misery. :)
 
Ad

Advertisements

D

David Mark

David Mark wrote:
[...]
if(typeof dojo == "undefined"){
dojo = {

And how could I forget. The final (they don't venture in here often)
lunatic touch. Based on some incomplete data and nonsensical
conclusions (something about being faster in IE) from a contributor
called "bill", they rushed to commit a change that removed the
declaration of this global (as well as a few others).

I tried to stop them, but they were intent to somehow improve their
performance without the "major hassle" of dealing with my renovated
version. The "no time, we're all busy" excuse comes up a lot with this
bunch. I say, if they don't have the time, why are they trying at all?
Who needs more half-baked blobs of JS at this point?

Furthermore, I think it bears mentioning that their "attr" method is
considerably worse than jQuery's (and that's really saying something).
And virtually all of Dojo (particularly the widgets) relies on it. For
those who aren't familiar with "attr", it uses a mix of get/setAttribute
(which are broken in many versions/modes of IE) and property access in a
seemingly random fashion that can only result from patchwork programming
by observation. Their bug-tracker is full of complaints about it, but
they apparently never spotted the pattern. Back when I was still
speaking to the owners, I was told their developers were all over my
attributes primer (this, after they had whined their way out of my
advice). I replied that the document has a copyright on it so they best
not try to lift it (not that they could carry it anyway). Last I heard,
they were preserving the old one for "compatibility" (LOL) and working
on a companion piece. Just when you thought it was safe to go back in
the DOM. :)
 
D

David Mark

Andrew said:
David Mark wrote:
[...]
if(typeof dojo == "undefined"){
dojo = {

And how could I forget. The final (they don't venture in here often)
lunatic touch. Based on some incomplete data and nonsensical
conclusions (something about being faster in IE) from a contributor
called "bill", they rushed to commit a change that removed the
declaration of this global (as well as a few others).

I tried to stop them, but they were intent to somehow improve their
performance without the "major hassle" of dealing with my renovated
version. The "no time, we're all busy" excuse comes up a lot with this
bunch. I say, if they don't have the time, why are they trying at all?
Who needs more half-baked blobs of JS at this point?

As a personal anecdote, I visited a friend of mine who works at a fairly
high-powered development house (lots of highly paid and skilled
developers who work on projects that cost $100s of thousands). They
recently got a javascript project to maintain/update a "web app" that
was build on top of dojo.

Well I learnt very quickly not to mention dojo in the presence of the
people working on the project. The mood instantly changes to murderous
(not helped by "told you so" attitude ;-) )

I'm not surprised. :)
I don't know if its dojo or just the way this project was originally
built but everyone is regretting taking on the project.

Likely a little bit of both. Imagine building a house with a hammer
made of jello and a water color of a saw. There's just no right way to
do it. You either admit that from the beginning or eventually go mad
trying to make it work.
Still it doesn't
make me want to suggest using it to anybody.

Don't suggest it to anyone you don't want to kill you. ;)
 
Ad

Advertisements

D

David Mark

David said:
Andrew said:
David Mark wrote:
[...]

if(typeof dojo == "undefined"){
dojo = {
And how could I forget. The final (they don't venture in here often)
lunatic touch. Based on some incomplete data and nonsensical
conclusions (something about being faster in IE) from a contributor
called "bill", they rushed to commit a change that removed the
declaration of this global (as well as a few others).

I tried to stop them, but they were intent to somehow improve their
performance without the "major hassle" of dealing with my renovated
version. The "no time, we're all busy" excuse comes up a lot with this
bunch. I say, if they don't have the time, why are they trying at all?
Who needs more half-baked blobs of JS at this point?
As a personal anecdote, I visited a friend of mine who works at a fairly
high-powered development house (lots of highly paid and skilled
developers who work on projects that cost $100s of thousands). They
recently got a javascript project to maintain/update a "web app" that
was build on top of dojo.

Well I learnt very quickly not to mention dojo in the presence of the
people working on the project. The mood instantly changes to murderous
(not helped by "told you so" attitude ;-) )

I'm not surprised. :)
I don't know if its dojo or just the way this project was originally
built but everyone is regretting taking on the project.

Forgot to mention. Tell them to email or IM. I can make it all better. ;)

Preventing developers from wasting massive amounts of time going down
blind alleys with Dojo "proper" (or jQuery or whatever) is what I've
been up to the last few months. There will be some promotional material
on cinsoft.net about this shortly. As for Dojo, I have rewrites of
every module and basically saw it all during the development process.
And you wouldn't believe what these people were faced with before they
found me (wrong answers and lousy patches at ten times the prices).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top