From: David Mark on
Matt Kruse wrote:
> On Apr 6, 8:34 am, Richard Cornford <Rich...(a)litotes.demon.co.uk>
> wrote:
>>> Yes ... but, IMHO, code modifications after framework's upgrade
>>> should be exceptions, not a regular practice.
>> That is a very reasonable expectation. The public API of a framework/
>> library/object/etc. could be thought of as a contract; you agree to
>> use it as advertised (documented) and in return its creator's/
>> maintainers undertake to keep it working as advertised.
>
> Within minor versions, I agree. But obviously each software author has
> the right to decide how frequently their API will change.
>
> More frequent = Lose developers because it's a PITA, but more flexible
> and ability to evolve and become more useful
> Less frequent = More backwards-compatible, developers love you, but
> less ability to add more functionality, so developers hate you
>
> It really varies a lot depending on the library in question.
>
>> Which doesn't mean things won't change over time but that change can
>> be managed, with new features added in parallel to features that
>> become deprecated (and eventually removed in the fullness of time).
>
> jQuery does do this, but not enough. It's very difficult to evolve an
> API like they have created, which highlights the fundamental flaws in
> it to begin with.
>
> As we've seen with Windows, the slow evolution of a platform and its
> API can be great for backwards-compatibility, which users love, but
> also make forward progress very slow and painful, which users hate.
> It's a fine line. Having a large, established userbase makes things
> more difficult. Perhaps jQuery got too big too soon, and John Resign
> missed the opportunity to re-think his initial design.
>
>> But published javascript frameworks/libraries have tended to be the
>> products of their author's first attempts to create such a thing.
>
> It's tricky, because most people who become experts in JS then shy
> away from frameworks and recommend not using them, so by its very
> nature, most frameworks are written by relative novices. Once they
> become popular, the weight of the support community, bug reports, new
> features, etc become the priority rather than the creator becoming
> more and more of an expert in the language. The demands of supporting
> a growing userbase (and the praise that usually comes with it) keeps
> the creator ignorant of his follies.
>
>> Indeed, when John Resig expressed the notion that nobody could justly
>> criticise JQuery until they had themselves created (and published) a
>> general purpose javascript library he was implying that this action
>> was itself the ultimate demonstration of javascript authoring
>> competence, rather than the reality where it is no more than one more
>> step on a learning curve.
>
> I have a different take on it.
>
> I think the argument is that unless you have written a public library
> and had to face all the other issues that come with it (community,
> support, evangelism, upgrades, testing, backwards-compatibility,
> different usage scenarios,...) then you lack the perspective needed to
> understand why some decisions are made. Even if a bug in a method is
> pointed out, there may be thousands of people who now rely on the
> wrong behavior, and fixing it will actually cause more pain than it
> prevents!

That's usually just an excuse to stay out of code that isn't understood
well enough to fix. Both Dojo and jQuery used it to justify their
attribute follies, despite the fact that the existing behavior changed
at the click of a button in IE8 (as well as between IE7 and IE8). It
doesn't make sense as nobody is relying on inconsistent behavior!

> And you get flooded with hundreds of emails and bug reports
> and have to somehow manage that. It gets very difficult to run a
> project the size of jQuery.

Especially when it is buggy as hell. :)

> I have put a number of things out for
> public consumption (though none have obviously reached the success
> level of jQuery) and have found it to be very overwhelming at times.
>
> This is why David's library is still not in the same arena as jQuery.

In terms of user base? No kidding. But it is light years ahead in
terms of being _ready_ for a large user base. Years later, jQuery is
still a flaky and ever-changing Beta test. Look at how many browsers
they've "discarded" over the years.

And how many users did jQuery have three months in? I didn't start
promoting it and encouraging users until the start of this year. It
will take time, but if my inbox/IM activity is any indicator, it is
growing very quickly.

> It may be quality code, it may work well, and it may have the
> beginnings of a community. But call me when he has tens of thousands
> of sites using his code and has successfully managed the whole
> process.

That seems like a pretty selfish attitude (especially as you were the
one calling for me to publish a library).

> Because that's a whole different game. It's easy for him to
> put out quick bug fixes now on a whim.

There's no problem with bug fixes if they don't change the expected
behavior. Bug fixes typically do the opposite. And it should be
telling that I can do that with a library that supports virtually
everything. Don't you think code that loads and runs in turn of the
century browsers, is almost fully featured (with cues as to where it
degrades) in browsers from the middle part of last decade and continues
to work in the latest is an indication of solidity that libraries like
jQuery, Prototype, etc. never approached. You are right, it's in a
different ballpark.

> It's easy for him to enhance
> the API.

Very easy. I just add new methods. That's the benefit of a design that
isn't hopelessly interdependent and tangled up in its own syntactic sugar.

> It's easy to get by with few examples and bad documentation.

It's not bad documentation, but unfinished documentation (and it is
getting there). And speaking of examples, I have a beginning user who
created a wonderful demonstration with little help from me (and English
isn't even his first language). He even created a custom effect with
virtually no guidance (or much documentation on how to do that). And he
remarked that even though the documentation was incomplete, the code was
very easy to follow. I don't totally agree as it is ugly in places, but
it is much better than the "elegant" gobbledygook found in most others.

And don't talk to me about examples. There are _tons_ of them in the
documentation and some pretty nifty ones on the Examples page that
actually write the code for you. More of those are coming. Why don't
you try making some? It will likely be a good learning experience in
terms of the library and cross-browser scripting in general.

>
> In short, he's not even playing the same game as jQuery yet.

Never was and never will be (but I don't think we're talking about the
same context).

> So his
> comparisons are still apples and oranges.

Other than tired metaphors, you aren't helping at all, are you?

>
>> So now, instead of the widespread re-think of the design
>> that would have been the second step otherwise, the library's public
>> API has become difficult to change at the same time as the author
>> becoming more aware of the shortcomings of the original design. The
>> combination of the need to change things that follows from the
>> shortcomings of the original design and the resistance to change
>> necessitated by a desire to support an existing user-base means that
>> changes get drawn out over an extended period, ultimately falling to
>> satisfy anyone as upgrades break existing code without ever having a
>> hope of addressing the more fundamental issues in the design.
>
> Exactly right, and this is where jQuery stands. And why it needs to be
> branched out to another project that can take the good stuff, throw
> away a lot of the bad stuff, and not be limited by compatibility or a
> obfuscated API.
>

Then it wouldn't be jQuery at all, would it? Brand names are worthless.
It's the people behind them that matter. And if the same people write
another script, I doubt I would recommend using it. A similar proposal
came from the Prototype people recently. I really wish they'd stay
home. But it likely won't matter as that brand's name is as much mud as
Dojo's. :)






From: David Mark on
Matt Kruse wrote:
> On Apr 5, 5:15 pm, David Mark <dmark.cins...(a)gmail.com> wrote:
>> So, isn't it about time you started using My Library instead?
>
> No. The poorly-documented API kind of sucks.

LOL. I assume you mean the documentation is poor (and I don't agree
that it is, but it is incomplete). The API is a world-beater (and the
OO stuff you can put on top of it is not too shabby either). It's the
best of both worlds! :)

>
> Despite its flaws and limitations, I recently used the "sortable"
> project of jQuery UI and found it very easy to create an interface to
> reorganize content by dragging and dropping things around.

You will never break out of this hypnotized state, will you? You know
how bad things are with code written on top of jQuery. Even jQuery
alone is a nightmare. Now you are going to try to keep jQuery _and_
umpteen other scripts in sync? And a lot of the add-ons still use UA
sniffing BTW. Good luck with that!

> All the
> options I wanted were there, and it was relatively painless to create
> in a small amount of time.

If you knew Time as well as I do... :) Haven't you been paying
attention? You'll pay it back with interest for sure.

> When you have that kind of high-level
> functionality ready to deliver, documented, tested, and with examples,
> let me know.

LOL. You want shiny widgets on a silver plate. They are coming, but
why don't you try writing some in the meantime. There's at least one
very good example up there now. And it's got a hell of an example that
even writes code for you.

And don't talk to me about testing. How effective has jQuery's testing
been over the years?

>
> Or I also did this:
> $('tr.task').live('hover', function() { $
> (this).toggleClass('hover'); });

So what? You can do that easily enough with mine (if that is your cup
of tea). The "live" thing is silly though. You would just attach the
listener to a container when the document is ready (which isn't hard). ;)

And how silly is it to rely on jQuery's CSS selector mess? As has been
demonstrated repeatedly, that's _begging_ for trouble for no good reason.

>
> Again, despite its limitations, this was a very easy way to add :hover
> support to some table rows in IE6. Does ML make it that easy?

Yes. There's no "toggleClass", but that's easy enough to create with
the existing add/remove/hasClass functions/methods. Just add it to the
E and Q prototypes (it's on my list).

>
>> You were the one that asked for it, remember?
>
> Umm, no.

LOL. Fall of 2007? You and Resig both kept saying you would really
love to see a GP library that didn't browser sniff. This is perhaps the
most infamous thread:-

http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/415949d1bcce6e6a/03c4d326340e7f7d?#03c4d326340e7f7d

....but IIRC, several others preceded it where you kept exhorting me to
publish my code for the good of mankind (or something like that). You
went on and on about how it could be improved with lots of people
working on it (ostensibly you, but you have never lifted a finger,
preferring to stick with jQuery to the bitter end). No recollection at
all? :)

>
>> Apparently, you wanted it all on a
>> silver plate from the start (e.g. community, repository, examples,
>> documentation) but didn't really do anything to help.
>
> I'm not interested in working with the author.
>

You don't know the author at all. ;)
From: David Mark on
Matt Kruse wrote:
> On Apr 5, 5:15 pm, David Mark <dmark.cins...(a)gmail.com> wrote:
>> So, isn't it about time you started using My Library instead?
>
> No. The poorly-documented API kind of sucks.
>
> Despite its flaws and limitations, I recently used the "sortable"
> project of jQuery UI and found it very easy to create an interface to
> reorganize content by dragging and dropping things around. All the
> options I wanted were there, and it was relatively painless to create
> in a small amount of time. When you have that kind of high-level
> functionality ready to deliver, documented, tested, and with examples,
> let me know.
>
> Or I also did this:
> $('tr.task').live('hover', function() { $
> (this).toggleClass('hover'); });
>
> Again, despite its limitations, this was a very easy way to add :hover
> support to some table rows in IE6. Does ML make it that easy?
>

Forgot to translate this for you (though I don't know why I am
bothering). You really don't need a toggleClass and I would consider it
ill-advised as you should add only on entering and remove on leaving.
The jQuery example is ambiguous about that, so prone to get out of sync.

Off the top of my head:-

// God forbid, I had to write a two-line function :)

var addOrRemoveHoverClass = function(e, b) {
var myEl = E(API.getEventTarget(e));

if (myEl.isTag('tr') && myEl.hasClass('task')) {
myEl[b ? 'addClass' : 'removeClass']('hover');
}
};

// One-liner to set up one table

E('somecontainerid').onRoll(function(e) {
addOrRemoveHoverClass(e, true);
}, function(e) {
addOrRemoveHoverClass(e);
});

// One-liner to set up x tables

Q('.somecontainerclass').onRoll(function(e) {
addOrRemoveHoverClass(e, true);
}, function(e) {
addOrRemoveHoverClass(e);
});

I'm sure discerning script authors can see how, despite a little more
typing (never a real concern) that will be minified away anyway, this
design is quite superior. And you can do it just as easily with the API
(see the docs as the API Reference is fairly complete with examples for
all, including attachRolloverListeners).

But that's not all. :) Suppose you want to write a widget with an OO
interface? On a whim, I have made public the inherit function to help
you out.

http://groups.google.com/group/my-library-general-discussion/msg/f8233a3bd6dd5e48

var MyWidget = function(id, doc) {

// ...

this.superConstructor.call(this, id, doc);
};

API.inherit(MyWidget, E);

MyWidget.prototype.addOrRemoveHoverClass = addOrRemoveHoverClass;

var aWidget = new MyWidget('mywidgetid');

// Adds context argument to listener calls, setting - this - object to
widget

aWidget.onRoll(function(e) {
this.addOrRemoveHoverClass(e, true);
}, function(e) {
this.addOrRemoveHoverClass(e);
}, aWidget);

Of course, you could also generalize this by overriding onRoll on the
MyWidget prototype:-

MyWidget.prototype.onRoll = function(fnOver, fnOut) {
this.superContructor.onRoll.call(this, fnOver, fnOut, this);
}

....Then you could change the line to:-

aWidget.onRoll(function(e) {
this.addOrRemoveHoverClass(e, true);
}, function(e) {
this.addOrRemoveHoverClass(e);
});

....and save a bit of typing. :) I'm just kidding.

Now, as you may have heard, the API is dynamic. This poses no real
problem for the application developer and, in fact, makes progressive
enhancement possible without having to touch anything (or even know
about anything) in the DOM:-

http://www.cinsoft.net/mylib-doc0.html#featuredetection

....and you sure can't do that with jQuery, Prototype, Dojo or any of the
others. In short, even if you skip putting in a gateway at the end, you
won't likely do any _worse_ than you would with the others. They are
known to fail miserably in environments unknown to their authors at the
time of coding (or ones they decide to stop "caring about" on a whim as
an excuse for their incompetence). In fact, having an immediate failure
(as would likely be the case if you skipped this next step can be seen
as preferable. Fouling up the log (that most users never see) is
nothing compared to fouling up the DOM. But regardless, it's easy.

// Declare in case library script was suppressed by firewall, network
failure, etc.

var E, API;

var MyWidget = function(id, doc) {

// ...

this.superConstructor.call(this, id, doc);
};

// Gateway

if (API && API.inherit && E && E.areFeatures && E.areFeatures('onRoll',
'addClass', 'isTag')) {
var addOrRemoveHoverClass = function(e, b) {
var myEl = E(API.getEventTarget(e));

if (myEl.isTag('tr') && myEl.hasClass('task')) {
myEl[b ? 'addClass' : 'removeClass']('hover');
}
};

API.inherit(MyWidget, E);

MyWidget.prototype.addOrRemoveHoverClass = addOrRemoveHoverClass;
MyWidget.prototype.onRoll = function(fnOver, fnOut) {
this.superContructor.onRoll.call(this, fnOver, fnOut, this);
}

var aWidget = new MyWidget('mywidgetid');

aWidget.onRoll(function(e) {
this.addOrRemoveHoverClass(e, true);
}, function(e) {
this.addOrRemoveHoverClass(e);
});
}

The gateway expression is equivalent to:-

(API && API.inherit && E && E.prototype.onRoll && E.prototype.hasClass
&& E.prototype.isTag)

Both are overly paranoid as - inherit - is going to be there (unless it
is somehow some _other_ API object). So is - onroll - assuming you
included the Event and Rollover modules. The E object will be there as
long as you included the DOM, Query and Object Wrapper modules. And so
on for hasClass and isTag. The builder makes it very clear what relies
on what snd the test page, with its console, makes it even clearer (you
can even watch the API functions in action during the tests). There are
many assumptions than can be made at build time. This is something I
need to document better in the API Reference, but for the moment, it
really doesn't hurt to check everything (and there are unlikely to be
consequences for a lot of it, even without a gateway).

The areFeatures methods were added to the wrapper objects recently (also
on a whim). But the second form is more efficient as it makes no
function calls. As you might guess, this method (and the private
function it calls) are never called internally. Speaking of whims, I
think I would like to have an object method that calls inherit (bless?)
on a passed constructor. Or maybe you want to add it:-

E.prototype.bless = function(fnSub) {
API.inherit(fnSub, E);
};

As a rule, the API never calls its own public functions (and certainly
doesn't do anything with wrapper objects). The (optional) object
wrappers call the API. That's how it should be (but isn't with any
other I know of).

Furthermore, it queries in exactly one function (gEBCN), which I think
is prudent, at least until I am sure that using the native gEBCN can be
consistent cross-browser (I've already got two DOM traversal forks and
three if you count the QSA add-on, with a new MSXML fork on the way).

And speaking of QSA, though I don't recommend it at this time, for what
it supports (which is more than most), at least the two columns (QSA and
not) are consistent. That's something the others failed miserably on.
There are likely quirks out there with QSA that nobody knows of, but
jQuery, Dojo, etc. don't have able non-QSA forks anyway, so what QSA
gets right, they sometimes get wrong (for all users with non-QSA
browsers). It's really unthinkable the mess they made with that (and
they knew exactly what would happen).

Questions? You know where to ask (and who will answer). ;) And for
those who want complete transparency for the server side end of it,
things like the above and/or complete documentation, comments, etc. You
know where to go (to cinsoft.net). You should have no trouble figuring
how to reach me.

Or you can stay on the jQuery merry-go-round and pray. Your call! :)
From: Hans-Georg Michna on
On Tue, 6 Apr 2010 06:34:16 -0700 (PDT), Richard Cornford wrote:

>The public API of a framework/
>library/object/etc. could be thought of as a contract; you agree to
>use it as advertised (documented) and in return its creator's/
>maintainers undertake to keep it working as advertised.

This hinges on the functions actually being documented in
detail. So let's look at jQuery's .attr(...) method's
documentation:

----- Begin -----
..attr( attributeName ) Returns: String

Description: Get the value of an attribute for the first element
in the set of matched elements.

attr( attributeName ) attributeName The name of the attribute to
get.
----- End -----

That's it. No mention what the function does when the attribute
exists, but has an empty string value, what it does when the
attribute does not exist, what it does when the attribute has
been modified with JavaScript earlier, etc.

The docs continue in that minimalistic style, for example, the
..attr(attributeName, value) doc does not say what happens when
value is undefined or an empty string.

One reason I now try to avoid jQuery is that I cannot read up on
what exactly it does.

This also generally shows that good documentation is essential
for good software.

Hans-Georg
From: David Mark on
David Mark wrote:
> Matt Kruse wrote:
>> On Apr 5, 5:15 pm, David Mark <dmark.cins...(a)gmail.com> wrote:
>>> So, isn't it about time you started using My Library instead?
>> No. The poorly-documented API kind of sucks.
>>
>> Despite its flaws and limitations, I recently used the "sortable"
>> project of jQuery UI and found it very easy to create an incontrterface to
>> reorganize content by dragging and dropping things around. All the
>> options I wanted were there, and it was relatively painless to create
>> in a small amount of time. When you have that kind of high-level
>> functionality ready to deliver, documented, tested, and with examples,
>> let me know.
>>
>> Or I also did this:
>> $('tr.task').live('hover', function() { $
>> (this).toggleClass('hover'); });
>>
>> Again, despite its limitations, this was a very easy way to add :hover
>> support to some table rows in IE6. Does ML make it that easy?
>>
>
> Forgot to translate this for you (though I don't know why I am
> bothering). You really don't need a toggleClass and I would consider it
> ill-advised as you should add only on entering and remove on leaving.
> The jQuery example is ambiguous about that, so prone to get out of sync.
>
> Off the top of my head:-
>
> // God forbid, I had to write a two-line function :)
>
> var addOrRemoveHoverClass = function(e, b) {
> var myEl = E(API.getEventTarget(e));
>
> if (myEl.isTag('tr') && myEl.hasClass('task')) {
> myEl[b ? 'addClass' : 'removeClass']('hover');
> }
> };
>
> // One-liner to set up one table
>
> E('somecontainerid').onRoll(function(e) {
> addOrRemoveHoverClass(e, true);
> }, function(e) {
> addOrRemoveHoverClass(e);
> });
>
> // One-liner to set up x tables
>
> Q('.somecontainerclass').onRoll(function(e) {
> addOrRemoveHoverClass(e, true);
> }, function(e) {
> addOrRemoveHoverClass(e);
> });
>
> I'm sure discerning script authors can see how, despite a little more
> typing (never a real concern) that will be minified away anyway, this
> design is quite superior. And you can do it just as easily with the API
> (see the docs as the API Reference is fairly complete with examples for
> all, including attachRolloverListeners).
>
> But that's not all. :) Suppose you want to write a widget with an OO
> interface? On a whim, I have made public the inherit function to help
> you out.
>
> http://groups.google.com/group/my-library-general-discussion/msg/f8233a3bd6dd5e48
>
> var MyWidget = function(id, doc) {
>
> // ...
>
> this.superConstructor.call(this, id, doc);
> };
>
> API.inherit(MyWidget, E);
>
> MyWidget.prototype.addOrRemoveHoverClass = addOrRemoveHoverClass;
>
> var aWidget = new MyWidget('mywidgetid');
>
> // Adds context argument to listener calls, setting - this - object to
> widget
>
> aWidget.onRoll(function(e) {
> this.addOrRemoveHoverClass(e, true);
> }, function(e) {
> this.addOrRemoveHoverClass(e);
> }, aWidget);
>
> Of course, you could also generalize this by overriding onRoll on the
> MyWidget prototype:-
>
> MyWidget.prototype.onRoll = function(fnOver, fnOut) {
> this.superContructor.onRoll.call(this, fnOver, fnOut, this);
^^^^^^^^^^^^^^^
> }
>

Typo. That's superConstructor.