Just to clarify. What I meant by 'coding in an XHTML style' is
things like using lowercase attribute names with quotations,
using closing tags even if they're optional, etc. such that
the markup is valid HTML resulting in an HTML DOM.
Self imposed discipline. That is usually a good idea in the absence of
externally imposed discipline (and perhaps regardless of it).
Could it be that people are simply doing their best to try and
find a library that is the lesser of evils to avoid the
disadvantages of writing everything themselves?
What are the "disadvantages" of writing everything yourself? Whatever
they may be on the plus side if you write something yourself you will
(or should) understand it, and there is a great deal to be said for
understanding the scripts that you use.
There a commonly asserted pre-supposition that the only alternatives
available are facilitating code re-use with the creation of large
general purpose libraries or to re-write everything from scratch each
time you do anything new. That polarized perception should be self
evidently nonsense to anyone who has copied an existing function form
one piece of exiting code to a new one, which will be pretty much
everyone who has got past pure copy-n-paste scripting.
Most of the bias in favour of large scale libraries comes with people
approaching javascript form other programming languages where having
large reservoirs of pre-created code always available to the programmer
makes perfect sense. Indeed so much sense that it becomes difficult to
see how that may not be true for all programming tasks. Which even
extends to the point where, when asked for justifications for using
large general purpose libraries some will not even consider answering
the question as a worthwhile exercise, even though articulating the
justifications would help to make it clear why the normal practice in
other programming environments does not necessarily extend well to
javascript.
There is not much thought given to the issues that follow from
broadcasting all the source code to the user and compiling it each time
it is executed. It should be fairly obviously that if it was necessary
to transmit over the internet, and then compile, all of the source code
for all the standard Java libraries, plus anything application
specifies, each time you wanted to execute any Java program then that
would make Java non-viable. But still that is the inevitable end point
of creating ever more capable (and so ever larger) general purpose
javascript libraries.
There also appears to be a tendency with the authors of such libraries
to react to criticism of the download size by seeking out code
compression strategies. This is something Dojo is attempting, and where
DoJo illustrates the folly of the exercise. In the 0.9.0 version the
file for distribution is 'dojo.js', which is 'compressed' (and actively
decompressed after it loads). The same code is available in full and
commented as 'dojo.js.uncompressed.js'. If you consider that HTTP 1.1
UAs tend to support compressed HTTP transmission it is significant to
consider how javascript source files will compress when considering
download size. When I zip compress 'dojo.js' the result is 25,903 bytes,
while if I remove the comments from 'dojo.js.uncompressed.js' and
compress it the result comes out at 25,862 (fractionally smaller). That
means that the 'compression' technique used in Dojo actually hinders zip
compression and so potentially increases download size, while its need
to de-compress on the client (with javascript) means that the total time
before the result is available to the user is increased by the process.
In truth code re-use is facilitated by any rendering of the specific
more general, from actions as simple as replacing inline code with
parameterised function calls. Given a huge spectrum of possible code
re-use strategies, with the large scale, highly capable, interdependent,
monolithic, general purpose javascript library being no more than a
point at one end of the spectrum, it is probably unwise to fixate on
that one strategy as being the only sensible option without being able
to articulate some pretty robust justifications for that position.
One of the issues faced by the author of a general purpose library is
the need to be truly general. This is well illustrated with one of the
much discussed browser scripting problems; the acquisition of accurate
position and dimension information relating to displayed DOM elements. A
general algorithm would take an element as input and determine the page
relative coordinates of its upper left corner and its width and height,
in some sense, as this is a description of some sort of 'containing
box', which does not necessarily have to be any specific box (in the
sense that CSS talks of boxes) but must be the same box for all
elements, and presumably a useful box to know about.
In the simplest case a DOM element will have offseTop/Left/Width/Height
and an offsetParent, and its position is the sum of all the
offsetTop/Lefts for all its offsetParents and its width/height is just
its offsetWidth/Height. But that is for CSS 'block' elements (as opposed
to inline, list-item, run-in, compact, marker, table, inline-table,
table-row-group, table-header-group, table-footer-group, table-row,
table-column-group, table-column, table-cell and table-caption) with no
borders or padding on the element and any of its offset parents, where
none of the offset parents have scrolling overflow, on browsers that
provide those dimension properties, and quite a bit else besides.
The general algorithm has never been worked out, though it is a
possibility and there are at least a few individuals on the planet that
could work it out and implement it. The reason that none of them have is
that they know that the result would be big (2000 plus statements),
complex, and far too slow to be of any practical use.
This leaves the general purpose library with a problem. It should have
element position and location reporting facilities, but if they are to
be truly general they will inevitably be non-viable because of their
performance and seriously contribute to the library's download bulk.
The best the general purpose library can be is proved a faculty that is
'good enough' for some set of common cases; a compromise. Which then
means that it will insufficient for less common cases (leaving anyone
using the library with no choice but add their own code for those tasks)
and at the same time the code is over the top for simplest cases,
risking sub-optimal performance for no good reason.
A less browser related example might be a 'safe' hash table
implementation. A very capable implementation may reproduce, say, all of
the Java HashTable class in javascript, with all of its methods and the
ability to have multiple live Iterators/Enumerators, while the simplest
may just facilitate the storing and retrieval of values using arbitrary
string keys. If a general purpose library is going to include such a
thing then the odds are it will tend toward the more capable end of the
range of possibilities, while the individual using it may only need the
minimum (making the runtime overheads of supporting live Enumerators
actively undesirable).
A third example of how the difference between the general and the
specific impacts on the general purpose library is the question of
framesets, and where any particular code is to be located in any
possible frame structure. You will often code testing - constructor -
properties against built-in constructor functions, or using -
instanceof - with the same subjects. That is all fine if you are working
with a single global object, but as soon as anyone is attempting to pass
objects about in a frameset structure such texts are invalid. There is
also the question of creating new DOM elements, where using the -
createElement - method of the wrong - document - object will be
disastrous in at lest some common browsers (including IE). So your
general purpose library has two choices; either assume a single global
object, and be insufficient for contexts where framesets are employed,
or do all the extra work to keep track of multiple frame contexts and so
be over the top whenever it is used in a single page site.
One of the characteristics of browser scripting is that it has become a
very diverse activity with many contexts of use; Intranet
sites/applications, web applications, e-commerce, promotional web sites,
public information services, entertainment, and so on. Some design
criteria for any one context do not necessarily even come into the
picture in some other contexts. And the starting point for design
decision making should be the purpose of the system being planned,
without any arbitrary a priori restrictions. And this is itself an issue
with general purpose libraries. Dojo, for example, only works (more or
less) with a few versions of half a dozen browsers (and will really fall
apart if exposed to anything else). That is too few for a public
information service in any jurisdiction that requires such services to
be accessible by law (as the fact that it will fall apart when it fails
will deny the possibility of clean degradation) but it may also be far
too many for a private web application (which may suffer from all the
branching inside the code in order to accommodate browsers that are just
not relevant in the application's context).
One of the arguments suggested in favour of general purpose libraries
(and also used to criticise them) is that learning the library avoids
the need to learn the details of handling web browsers directly. Once
you realise that the compromises that the general purpose libraries must
make (to be as capable as is realistic (for their authors) but no more)
mean that any single general purpose library cannot sensibly be used in
all application contexts you see the need is not to spend time learning
a single general purpose library but instead potentially a whole range
of such libraries, and the bigger and more capable any single example is
the more work is involved in learning to use it. And given that it can
make a lot more sense to spend time learning to script web browsers
directly than to learn the APIs for a series of libraries that may still
not be suitable for all to applications that may come up. (This is
particularly true when standardisation of browser object models means
that 80-odd% of what could be learnt would then be applicable to most
scriptable browsers).
So what is wanted is a code re-use strategy (as we will all agree that
writing everything form scratch for each project is insane) that
maximises the proportion of code being re-used, produces an easily
maintainable and reliable end result and is sufficiently flexible to
produce appropriate code of any given application context without
pre-imposing arbitrary restrictions on the design process or being over
the top in the less complex contexts.
Inevitably there is some disagreement as to how best to achieve this
outcome, but it is fairly obvious that larger-scale general purpose
libraries will not satisfy those considerations (with their overriding
emphasis on code re-use at the cost of seemingly all else).
My preferred strategy is to build code from a large collection of
relatively small interchangeable modules designed around interface
definitions, where any single interface may have numerous
implementations. The resulting architectures start out with a lowest
level that is a layer of modules that abstract out the differences
between browsers by handling them internally. Above that are more layers
of modules that depend upon the interfaces provided by the previous
layer and expose their own interfaces for more complex and task specific
actions, and above that some number of similar layers ending in the
application specific control logic code that must be unique to each
specific action.
The lowest layer includes only items form the collection of interface
implementations that are employed in the context, sufficient for the
context and no more, and usually very well tested. Given a particular
task, say the reporting of view port dimensions and scroll values, a
single interface is used, but any number of objects may exist to
implement that interface. So while a cross-browser version may attempt
to provide that information wherever it is available, in a context where
only a limited set of known browsers are to be used a much simpler
version exists to be used in its place. While any code that employs the
interface does not need to care about any more than getting a reference
to an object that implements the interface, and so does not care about
the specifics of how that is done in the context.
This strategy allows issues like the unreasonable complexity of the
truly general element position reporting algorithm to be avoided. In any
real context it is possible to know enough about which positioning
information is required and why it is required to sidestep most of
complexity of the general problem. If no elements of relevance are to
have scrollable contents, or borders, or be anything but block elements
the task goes from the complex back to the quick and simple, and indeed
enough can be known about the context that many optimisations can be
implemented inside the object providing the element position reporting
interface. It may be the case that a theoretically huge number of such
implementations would be necessary to accommodate all the permutations
but in practice if you start by only implementing the ones that are
needed when they become needed you end up implementing the most
recurrent requirements first (and so creating the most re-useable
objects) and may never actually encounter a real world situation where
the more involved position reporting problems need to be addressed.
Consider what happens when re-design results in maintenance issues. For
the positioning problem; suppose someone re-designs the presentation and
ends up adding elements with scrolling overflow where they had not
previously existed. The object implementing the position reporting
interface can no longer cope as it was never designed to do so. But
either the collection of objects implementing that interface already
contains one that can cope, or a new implementation can be created and
added to that collection. The problem is solved by swapping one object
for another that implements the same interface (but takes more into
account internally) and all of the rest of the code is unaffected by the
change.
The collection of such interchangeable modular interface implementations
from which actual projects are built may be regarded as being a library
(in some sense) but it is not something that can be presented to the
wider world as a library because it is inherently incomplete by design.
The design work, the intellectual effort, goes into designing interfaces
that can sit on top of varying implementations and usefully participate
in flexible hierarchical structures of code. The actual creation of the
objects implementing the interfaces is on an 'as needed' basis, and
while the expectation is that those objects created should then be very
re-useable (in similar contexts, with the likely re-occurring contexts
also being those likely to occur early in the process), the objects for
the more unusual situations may never be needed by any individual, and
so never be created and added to the collection.
In my short time on c.l.j, I have seen many criticisms of
JavaScript libraries
Yes, it can be very easy.
but few recommendations. It could be that they simply got
lost in the noise.
No, there are few recommendations, and the few people making such
recommendations tend not to be doing so on an informed basis.
Are there any JavaScript libraries that you can recommend over
reinventing wheels?
You are certain that those are the only two alternatives?
I checked the FAQ and didn't see anything.
I'm also curious if the folks criticizing the 'popular'
JavaScript libraries (or their authors) have attempted
to improve the code - either by direct contribution or
via educating the authors.
If the people making the criticism are of the opinion that 'improvement'
would involve a significant re-thinking of the concepts underlying the
enter library design any such attempts to 'improve' would be very likely
to be disregarded by the authors of those libraries.
On the other hand "the folks criticizing" have already done a great deal
to improve the code in these libraries, though maybe not that directly
(or with that specific intention). I my own case inventing what is
apparently destined to be called "Crockford's module pattern" in early
2003, and then participating, with other regular contributors to this
group (and also "folks criticizing ... "), in the development of its
applications over the following two years, has had a very visible impact
on the code in any recent library you could name, and mostly for the
better.
(It is interesting watching the wider world re-inventing the wheel when
it comes to the "Crockford's module pattern". For example, having
started with the singleton implementation used in the YUI blog to
demonstrate the idea (which is an application of the idea from August
2003)-
<URL:
http://nefariousdesigns.co.uk/archive/2007/08/javascript-module-pattern-variations/ >
- shows someone re-tracing the evolution of the scheme and ending up
back with a single function interface, which parallels in structure the
very first examples of non-'Class' related modules I published in May
2003).
Then there is the growth of the understating of, and subsequent use of,
javascript's closures in general. A trend that is also evident in recent
library code and a trend in the wider world that can almost entry be
traced back to my 2004 article on javascript closures written for the
group's FAQ.
Over the years various contributors to this group have written probably
the equivalent of sizable books on the subject of javascript. Mostly
directed towards the better understanding of the language and better
design in its applications. And this has all been done in public (and
archived) in a context where anyone who wants to is free to participate.
If the authors of those 'popular' libraries have preferred to ignore
that and hide away in their own little worlds then that is hardly the
fault of anyone who criticises their code here.
They are beyond hope if the people responsible have their egos so
heavily invested in their creations that they can never recognise their
mistakes.
But to some extent these things become the victims of their own success
as once they have been 'released' and acquired a user base addressing
fundamental design faults becomes very difficult. Given the limited
technical understanding of javascript on the part of their authors, as
demonstrated in the code they write, in most cases it might have been
better if the authors had held off 'releasing' anything until they had
taken the time to learn the language, and gain some experience using it,
because during that time they may have learnt enough about browser
script design issues, and been exposed to more debate related to the
subject, to have started their libraries on a better footing (or in some
cases not started them at all).
Richard.