Monthly Archive for April, 2009

The jQuery Syndrome

jQuery is a JavaScript library that makes the portable manipulation of the DOM easier. It provides primitives for selecting DOM elements using a simple CSS-similar syntax (courtesy of the Sizzle selector library), and functions for applying effects to the selected elements.

A few typical examples:

// Show all paragraphs on the page, even hidden ones.
$('p').show();

// Select all cells with class "important" within table "results"
// and make their background red
$('table#results td.important').css({background:'red'});

// Wait until page has loaded, then find all spans with class "mail",
// replace any '[nospam]' in their contents by '@' and add 'mailto' links
$(function(){
  $('span.mail').each(function(){
    var mail = $(this).html().replace('[nospam]', '@');
    $(this).html('<a href="mailto:'+mail+'">'+mail+'</a>');
  });
});

This ability to add dynamic behavior to elements at will by a select-and-apply process is extremely useful. For the HTML writer, adding behavior becomes as easy as adding a class to an element (using the above code, all you need to turn a piece of text into a mail is to put a span class=”mail” around it, no additional JavaScript required).

Yet, this approach does not scale well. Attempting to approach any non-trivial problem with a select-and-apply architecture inevitably leads to a heap of annoying problems.

The jQuery paradigm is $(target).operation(configuration); which implies that the dynamic data is within the target. This is what happens, for instance, in the mail rewriting example above: the address to be rewritten appears in the DOM, not in the JavaScript. This is one of the reasons why jQuery is so concise: most of the data is not specified as part of JavaScript code.

The problem appears when the data structures you manipulate are complex, because accessing data within the DOM is orders of magnitude harder than manipulating JavaScript data even with jQuery (and is utterly unacceptable with raw JavaScript). As long as your data is just a piece of visible text, or  the DOM structure itself, you will be fine. But as soon as you need additional data and invisible fields, you will start storing that data in attributes (<a name=”your data here”></a>) and the overhead of accessing it will kill both your productivity and your page’s performance.

It also appears when the behavior involves several interacting pieces on the page. Independent manipulation of pieces poses no problem in the jQuery paradigm, but what happens if two parts of a script attempt concurrent manipulation of a single piece?

Consider a very simple example that contains an image with a “hide” button that hides the image, a “show” button that shows the image, and a “delete” button that deletes the image. We want the hide and show effects to involve some animation. No button should be pressed while an animation is playing, so it is necessary to have all buttons be disabled whenever an animation starts, and then enable only the acceptable buttons when the animation ends. This gets increasingly complex as time passes, unless you simply use a lock: set the lock variable to true when the animation starts, set the lock variable to false when the animation ends, and have all buttons do nothing if the lock variable is set to true.

What I call the jQuery syndrome is the naive approach to making a page dynamic by using the select-apply operation on every item that is meant to be dynamic, and noticing a few days later that the data is so hard to extract, or the interactions so hard to synchronize, that you will need to refactor everything into a more scalable architecture.

My preferred approach to jQuery-based architecture, as detailed in an upcoming JITBrain article, is to have a central JavaScript object that controls the data for what is being displayed (usually one for every independent piece of your page). This object has a print() function that constructs or updates the corresponding DOM elements on the page and binds their events to its own member functions.

So, a typical event (onCreate, onClick…) happens as follows:

function onShowButtonClick()
  update data
  this.print() 

function print()
  update DOM from data
  bind show button click to this.onShowButtonClick

Of course, in practice there will be a lot more binding going on, since every button has to be bound to an action. Then, depending on how much time you are ready to spend on the matter, you can implement your print function as a “delete everything, replace with new values” or as an incremental update of the DOM areas that do not match the internal data.

JITBrain – Item Model

I have posted the articles explaining:

The next step will be to discuss the AJAX-based interface, which can already be seen (at least in part) on the demo website by creating yourself a new account:

http://jitbrain.nicollet.net

JITBrain currently contains 2224 lines of PHP code, and not all of them have been discussed yet. I will start counting the Javascript soon, as well.

   25 config/db.php
   54 config/domain.php
   17 config/error.php

   31 controllers/ajax-post.php
   19 controllers/confirm.php
   52 controllers/do-login.php
  107 controllers/do-reset-password.php
   82 controllers/do-signup.php
   70 controllers/files.php
   24 controllers/index.php
   17 controllers/login.php
   27 controllers/reset-password.php

   83 models/authentication.php
   40 models/group.php
   98 models/groupusers.php
  170 models/item.php
  292 models/itemrevision.php
   34 models/user.php
   39 objects/html.php
   77 objects/lazy.php

   21 utils/array.php
  154 utils/db.php
   67 utils/error.php
   31 utils/item.php
   10 utils/js.php
    9 utils/localization.php
   53 utils/pervasive.php
   27 utils/redirect.php
   88 utils/request.php
   40 utils/session.php

   27 views/confirm.php
   24 views/itemlist.php
   69 views/loginpage.php
   29 views/newitemfield.php
   18 views/page404.php
   40 views/plainpage.php
  101 views/resetpassword.php
   58 views/twocolform.php

 2224 total

Arrays: additionnal commas

This is starting to look like “attack of the arrays”, but there are so many interesting things to discuss!

Consider for a moment these languages: C#, Java, C++, Objective Caml, PHP, JavaScript. All these languages support a form of array literal (even though in some languages these literals are restricted to initialization purposes only). All of them use the value-separator format:

// C#, Java, C++
{ 1, 2, 3, 4 }

(* Objective Caml *)
[| 1; 2; 3; 4 |]

// PHP
array( 1, 2, 3, 4 )

// JavaScript
[ 1, 2, 3, 4 ]

When you need a program in one language to interact with code written in another language, a possibility is to have the origin language generate code in the target language and then dynamically link the generated code with the target. This could be Objective Caml generating data for a C program that’s compiled on-the-fly with TCC, XSLT being used to generate PHP code from an XML file, or PHP generating JavaScript code to be embedded in a web page.

There are two ways of generating array literals. One is to generate every element independently and then collapse the string array into a single string, which inserts the separators in-between elements. This could be PHP’s implode, or Objective Caml’s String.concat. This generates a clean array.

If you didn’t plan out your code correctly (or if you’re using XSLT 1.0 and have an approach that’s too complex to allow the use of the XPath ‘position()’ function), or if you have unusual performance requirements such as having to push data to a client as fast as possible, you will end up instead having to generate the array string directly, without the ability to collapse it from an array of strings. The problem of separators appears: you have to determine which element is the last one, so you don’t append a comma (or determine which one is the first, so you don’t prepend a comma).

The good news is that some languages let you add a surnumerary separator at the end of an array literal, so instead of the traditional { a, b, c } you get a less obvious but more easily generated { a, b, c, }.

Pop Quiz

Which of the above languages let you define an array literal with an additional comma or semicolon at the end?

Answers:

  • C++ as per the optional comma shown in the grammar outline in 8.5 §1
  • Objective Caml lets you append optional semicolons in arrays, lists, expressions and records, and prepend optional pipes in pattern matching and variant definitions.
  • C#, Java and PHP do as well.
  • JavaScript should.

Should? In the design of ECMAScript, there are two opposing forces: on the one hand, the ability to add a trailing comma with no semantic effect, and on the other hand the ability to leave empty array elements by placing nothing between the commas. This is all explained in hairy detail in ECMAScript 3 [pdf] 11.1.4 and means, mostly, that every comma found directly after another comma increases the length of the array by one before continuing processing. And all of this leads to somewhat confusing results:

// #1: two values, length 2 (as expected)
[a,b]

// Removing a from #1: length 2 (as expected)
[,b]

// Removing b from #1: length 1 (what??)
[a,]

This is ultimately a matter of whether something like [,] should count as a two-element array or a one-element array. ECMAScript 3 (and subsequent versions) settled for the one-element array, which makes ECMAScript easier to write (since you can move around elements in an array with their associated comma so you don’t have to type/erase commas) but harder to read.

Too bad Internet Explorer disagrees. Consistency matters and therefore:

// Removing b from #1: length 2
[a,]

So while it is entirely acceptable to use a terminating comma in JavaScript without ill effects on the rest of the array, portability dictates that if you support Internet Explorer (6 or 7) then you should avoid the terminating comma or have a clean way of handling the trailing undefined element that will be generated.

array_fill

PHP provides the array_fill function to create an array containing identical values a fixed number of times. To quote the example on the documentation page, code such as:

$a array_fill(56'banana');

Generates this kind of array:

Array
(
    [5]  => banana
    [6]  => banana
    [7]  => banana
    [8]  => banana
    [9]  => banana
    [10] => banana
)

But the documentation does not answer an important question: are the values inserted into the array merely copies of the argument, or are they actual references to the argument?

This may not seem like much, but PHP5 introduces manipulation of objects by reference (since working by value seldom plays nicely with object mutation) so it can be interesting to know how an array of objects reacts.

The result is quite interesting. Consider the following code:

$obj = (object)array('x' => 0);
$arr array_fill(02$obj);
$arr[0]->1;

The expected output, if all the elements are independent copies, is that only the first cell will have a value of zero:

Array
(
  [0] => object(stdClass)#1 { ["x"] => 1 }
  [1] => object(stdClass)#1 { ["x"] => 0 }
)

But what really happens is that all the cells in the array actually reference the original object, which means the array will actually look like this:

Array
(
  [0] => object(stdClass)#1 { ["x"] => 1 }
  [1] => object(stdClass)#1 { ["x"] => 1 }
)

Oops! I hope you weren’t relying on that function for filling an array of objects.

On the other hand, since arrays are manipulated by value, code such as …

array_fill(0, 10, array_fill(0, 10$value));

… does indeed create a 10×10 grid of independent cells.

Snippets Again!

Jeff Atwood has expressed on his blog what he feels are the advantages and disadvantages of copying code from the web, which sound a bit like my old rant on snippet sites.

I wish he had discussed the advantages and disadvantages of pasting code to the web, but he only tangentially noted it:

The programmer’s ego may drive her to only publish code that she believes is of sufficient quality.

And again, my old idea on snippet-oriented design would apply: if you strive to write your code so that it can be published on the web, your ego will drive you to write code of sufficient quality. Ego works both ways, even if not with the same magnitude.

Aside from that, using a GUID could be an interesting idea for finding modified versions of a certain bit of code.

Another, which would involve a less distributed approach, would be to use an existing web mechanism: trackbacks. If you post a code snippet on your website, and your site software supports trackbacks, you can merely include a link to a common snippet sharing server (say, http://www.snpts.com/). The trackback would ping the snippet server, who would crawl the pinging post in response, extract the code, and store a link. That server could then use search algorithms to determine similar code, so you could literally paste a snippet you found on the web onto a search form, and get a list of blog entries that entered similar code. While globally harder than merely adding a GUID (that server has to be built), it’s easier on the people posting the code because they can just add a link to the snippet site (and how long before “post to snpts.com” becomes a standard button among “digg” and “twitter” ones?)

But the real question is, does snippet re-post happen often enough to warrant such an approach? How often does a copy-paster upload the corrected version of his code, or even correct it at all? Would anyone bother with the GUID if most of the time there is only one copy, perhaps two or three?

JITBrain – The Graph

Lo and behold: all the modules available in JITBrain so far, and their interdependencies:

Click to enlarge

These modules have been automatically extracted from the source code by grepping for “(.*)::” and “new (.*)”, then the class-file associations have been determined using the autoloader code, and the result was fed to dot (from Graphviz) to generate the graph.

JITBrain – Login Reloaded

The login page is functional and skinned! You can now login, sign up, retrieve your password, and if you were trying to do something that requires an authentication, you will be able to resume that once you authenticate. The corresponding articles have been added to the ongoing series: Delayed Requests, Password Recovery and Stylesheets.

The next step is to design the core of the JITBrain application: the form that lets the user add an issue to the tracker. It has to be carefully balanced for optimal usability, so expect a lot of tweaking and AJAX programming (and an introduction to jQuery).

So far, JITBrain is 1286 lines of PHP (not counting the CSS, obviously):

   20 config/db.php
   54 config/domain.php
   17 config/error.php

   19 controllers/confirm.php
   50 controllers/do-login.php
   99 controllers/do-reset-password.php
   78 controllers/do-signup.php
   43 controllers/files.php
    3 controllers/index.php
   17 controllers/login.php
   25 controllers/reset-password.php

   83 models/authentication.php

   77 objects/lazy.php

  115 utils/db.php
   67 utils/error.php
   52 utils/pervasive.php
   27 utils/redirect.php
   88 utils/request.php
   40 utils/session.php

   27 views/confirm.php
   68 views/loginpage.php
   17 views/page404.php
   37 views/plainpage.php
  105 views/resetpassword.php
   58 views/twocolform.php

 1286 total

Enjoy your read!

JITBrain – Authentication Model

Posted a new article: Authentication Model. Also made some retroactive modifications to take into account new details about DomainConfig::Url.

The next steps are:

  • Handling the interruption in the user action created by the login requirements, so that the user activity is resumed after the process.
  • Resetting the user password.
  • Applying some lipstick to the login page to make it look better, and include some JavaScript.

JITBrain contains 843 lines of PHP so far.

   20 config/db.php
   48 config/domain.php
   17 config/error.php
   45 controllers/do-login.php
   66 controllers/do-signup.php
    3 controllers/index.php
   14 controllers/login.php
   70 models/authentication.php
   77 objects/lazy.php
  115 utils/db.php
   67 utils/error.php
   52 utils/pervasive.php
   27 utils/redirect.php
   40 utils/request.php
   40 utils/session.php
   67 views/loginpage.php
   17 views/plainpage.php
   58 views/twocolform.php
  843 total

JITBrain

Some of you may have wondered, what is this secret project he is working on?

The project is called JITBrain. In itself, it’s nothing quite groundbreaking, merely an issue tracking platform that services two categories of users:

  • Individuals that have a lot to do but never seem to manage it. These are helped by features such as extremely simple todo-list manipulation, a search engine for looking at previous tasks and retrieving important information, and helpful statistics.
  • Teams that must collaborate on projects. These are helped by features such as issue tracking, simple workflows, attached links and files, planning poker, reporting charts, and motivational gizmos.

The unusual thing about the project is the development method: it builds upon my earlier ramblings on snippet-oriented development (developing quality software by actively thinking of the people who will read and reuse the code) to actually become an advanced tutorial in itself. This brings yet another benefit, since the code is not only designed in short bursts of concisely explained functionality, but a complete documentation and log is being written along with it.

As such, it has the additional purpose of serving as a simple reference for “classic mistakes” both in technical and functional areas in the development of a website.

The tutorial advances along with the development of the system, which means you can see the tutorial or look at the website.

HTML Alignment

LE PORTIER (le poursuivant):
Holà ! vos quinze sols !

LE CAVALIER:
Holà ! vos quinze sols !J’entre gratis !

LE PORTIER:
Holà ! vos quinze sols ! J’entre gratis ! Pourquoi ?

LE CAVALIER:
Je suis chevau-léger de la maison du Roi !

I can guarantee that, regardless of your font size or face, “J’entre gratis!” will be aligned horizontally in-between “Holà ! vos quinze sols !” and “Pourquoi?”, as it is expected to be (this is an excerpt of Cyrano de Bergerac, written in verse, and since the three sentences are part of the same verse they have to be written this way for better understanding).

How and why do I guarantee this? What I wrote is actually:

LE PORTIER (le poursuivant):
Holà ! vos quinze sols !

LE CAVALIER:
Holà ! vos quinze sols ! J’entre gratis !

LE PORTIER:
Holà ! vos quinze sols ! J’entre gratis ! Pourquoi ?

LE CAVALIER:
Je suis chevau-léger de la maison du Roi !

Then, I simply set the style to “visibility:hidden” on the redundant parts. They are invisible, but still taken into account for the page layout. So, the horizontal offset of “J’entre gratis!” will be the width of the “Holà! vos quinze sols!” sentence repeated above.



693 feed subscribers
(readers who polled a feed this week)