BeFruit

Wednesday, June 27, 2007

Structuring JavaScript libraries: modularity

JavaScript pop up calendar is a common need, so why does none of the libraries I found match my needs. With Ajax are we often adding an "auto suggest" feature, so why isn't there a library that works in all the situations like auto complete, JavaScript dropdown lists and on-the-fly search boxes?

The answer is simple, all those libraries try to conceal the apparently contradictory needs that are generalization and customization.

We need to generalize to have calendar functions that can be used in all the situations without any modification. To achieve that we strip from the library all the features that are specific to a given case. We end up having a library that does almost nothing, like simply returning days of a month organized in a 7 days × 6 weeks grid.

We need to customize to have calendars displaying week numbers, allowing date range selection or time picking. To achieve that we add the features, and for each of them a flag that we can activate or not, allowing us to enable the feature only when needed. We end up having a library continuously growing, with numerous parameters and difficult to maintain.

The JavaScript language allows easy integration of multiple libraries with the notions of callbacks and object oriented programming.

The idea is simple: define core features and write separate libraries for each of them. Define the data structure that will allow communication between them. Define simple default behaviors for features that can be overridden with additional plug-ins.

If you use only the core library, you have a simple set of features easy to understand and with few parameters. You can plug more features if you need them. You can rewrite your own plug-in - and only this one - if it does not exactly meet your needs.

For a calendar, the code feature is to display a date grid. The data structure is a date value, with flags indicating if a date range is selected. The additional plug-ins could be week number information, enabling selection of a month or a year, adding a second calendar for range selection, allowing time picking.

Each of these plug-ins is obviously small, easy to maintain and debug. You reduce the amount of code to download to the client if you don't use all the features.

A common mistake is mixing HTML rendering with internal logic. Avoid that at all cost, and eventually make the render engine a plug-in.

Creating modular libraries may seem more complicated at first look, but forcing you to think of the structure before you start will make your ideas clearer and you will actually reach your goal faster.

Labels: ,

Friday, June 22, 2007

Structuring JavaScript libraries: documentation

Very few developer like to write documentation. The library they write is clear to them and when the hard work of programming is finished, it is difficult to decide to write the documentation. Unfortunately, without a documentation, your library is completely unusable.

The aim is not to write a long documentation, so the first step is to find what kind of documentation is the most efficient. That means: what is the shortest documentation that will be clear and precise enough.

The easiest one is to write examples. Find a set of symptomatic and concrete usages of you library. This will help users to start using it.
Later when they will need advanced features, another kind of documentation - the technical reference - is a better choice. The reference shortly describes each function, its parameters and call conditions.
Finally I suggest that you write a global description of the library, its philosophy, and general rules that have to be respected. And put it at the beginning.

All together, you have a complete documentation that is easy to write.

The best place for the technical reference is within the source code. Each time you add a new function, write a short description. Each time you modify the function, you won't forget to update the documentation.

Some would say that in JavaScript, the size of the library is critical for download time and interpretation time. Therefore they don't write comments, write compact code stripping spaces and newlines. The code becomes unreadable and difficult to maintain.
This is true but there is an easy solution. Use the JavaScript compactor and provide two versions of your library: the full documented code useful for learning and debugging, and the compacted file for production use.

You don't have any excuse not to write a good documentation. It is not that difficult and you will be the first to benefit from it when you will later reuse the library.

Labels: ,

Wednesday, June 20, 2007

Structuring JavaScript libraries: namespaces

When you write a JavaScript library, it is important to respect some rules if you want that the library is widely adopted.

The first rule is to avoid conflicts with other JavaScript. This is called leaving the smallest footprint. That means that global variables and functions should be avoided, because another library could accidentally use the same name. The best way is to define a single variable which contains all your code like this:

var MyNamespace = {
    myGlobalVariable:23,
    myFunction:function(x){
        return x * x + this.myGlobalVariable;
    }
};


You should only choose a unique "MyNamespace" that nobody else will happen to use. And if a conflict happens, you only have to change a single name on one place to resolve it.
Then you call your function like this:

var y = MyNamespace.myFunction(4);

There is even a way to leave no footprint at all by hiding your code into an anonymous function:

(function() {
    var tDays=['Monday','Tuesday','Wednesday'];
    for (var i=0; i<tDays.length; i++)
        alert(tDays[i]);
})();


The drawback is that you can not reference that code from outside.

The second important rule is to write a documentation, and I will detail it in another post.

Labels: ,

Thursday, June 14, 2007

Typed variables in JavaScript

JavaScript is a rather permissive language, and it lets you write code without annoying you with variable declaration or typing. It is good for simple functions like this:
function selectOptionByValue(oSelect, value){
oSelect.selectedIndex = -1;
for (i = 0; i < oSelect.options.length; i++){
if (oSelect.options[i].value == value){
oSelect.selectedIndex = i;
break;
}
}
}

with the following HTML:
<select id="qualitySelect">
<option value="0">Bad</option>
<option value="1">Average</option>
<option value="2">Good</option>
</select>

if you call:
selectOptionByValue(document.getElementById('qualitySelect'), 2);

the "Good" option is selected.

But what really happened? The function compared the value "2" associated with "Good" with the integer 2.
This is convenient as you don't have to think of it, it works.

But in more complex projects, this permissiveness can make debugging extremely difficult. If you assigned a variable that you were considering as an integer with a string value, all your next processing will fail, but JavaScript will not complain. So a bug that could be detected early arises much later, in a completely different place.

There is not a single solution for this, as JavaScript is not a compiled language where the compiler could signal incorrect type assignments.
The first thing is to declare all variables with "var".
If you want to compare two values in a typed way, use === instead of == and !== instead of !=. '2' == 2 is true where '2' === 2 is false.

A good starting point is to use a tool like the free JSLint that warns you about all the risky code that could hide potential bugs.
This will not eliminate all the bugs from your code, but help you concentrate on the logic instead of the syntax.

Labels: ,

Tuesday, June 5, 2007

JavaScript Closures and memory leaks

You sometimes use techniques unconsciously, and you discover it later when trying to locate a bug. Closures in JavaScript is one of those. If you create functions dynamically, you often create a closure:

function formatMoney(sFormat){
    return function(iAmount){
        return sFormat.replace('[amount]',iAmount);
    }
}
var formatEuro=formatMoney('[amount] €');
var formatDollar=formatMoney('$[amount]');
alert(formatEuro(12)+' - 'formatDollar(23));

displays "12 € - $23".

You can notice that the sFormat variable, declared outside the function definition is still present when the function formatEuro is actually called. This is possible because JavaScript creates an object with the dynamically created function and its context with the local variables.

Why does this provoke memory leaks? Well, it shouldn't, as JavaScript has a garbage collector, and the objects created on the fly are freed when needed. But some browsers (IE?) are worse than others on that aspect, and circular references, particularly between JavaScript and DOM objects remain locked.

Taking care of memory leaks becomes more important as we create Ajax applications that do not jump from page to page, and do not give an occasion to the browser to completely flush its working memory. Badly designed Ajax applications can increase the memory used by your browser to a point that locks your computer completely.

A good article at ibm.com explains what are the common patterns leading to memory leaks, and a few solutions to avoid them.

Labels: ,