Monday, August 06, 2007

Befriending Javascript

Jerry Seinfeld had once said that according to most studies, people's number one fear is public speaking. I am not very comfortable speaking in public, but as far as Web application development is concerned, my numero uno fear factor was Javascript. Since then I tended to avoid this beast like anything and promptly started proclaiming myself as the server side guy.

Days have changed, positioning of Javascript as the ubiquitous computing runtime for the Web has started getting more traction. We are seeing more standards evolving, Rhino bundling with the JDK has given the server side guys more options towards DSL based designs. Lots of stuffs are happening in the scripting world, in general, and Javascript, in particular. In one of my earlier posts, I had described how we used server side scripting to externalize business rules from a business application. This post is a continuation of my belated attempt at befriending Javascript, with a special mention about the functional programming capabilities using the language. Have a look at the following snippet :


map(compose('+1', '*2'), [1,2,3])



which produces [3, 5, 7]. This is Functional Javascript.

In one application, I had to do some list processing as part of client side validation in a financial application and get counts of tax/fees which exceeded a predefined max. I started the usual imperative way using the nuts and bolts of if-then-else and for loops. Things looked ok initially, but started getting clunkier when lots of similar variants in processing logic came up and the code started looking boilerplate. Some googling pointed out that with Javascript's functional power you can kick it up another notch. You can program to the map-reduce paradigm and make full use of Javascript's higher order functions to carve out your client side validation library.

Here are some snippets using Oliver Steele's functional Javascript ..


count_grt_max = function(array, max) {
  function count(total, element) {
    return total + (element > max ? 1 : 0);
  }
  return reduce(count, 0, array);
}



And when the validation logic gets more complicated with more and more clauses being added, use the full power of functional Javascript ..


// get the sum of tax fee values which pass the
// minimum and maximum criteria validations

reduce('x y -> x + y',
    0,
    select('>' + max,
        select('<' + min, tax_fee_values)));



While this may seem an unnecessary functional engineering at work for a seemingly trivial task, there are situations where you surrender yourself to the temptation of beauty and sacrifice an element of utilitarianism. And, of course there are use cases in every application, which do not need the raw harness of your favorite performant enterprise language. Use the many functional javascript libraries to spruce up your client side scripting - remember you can use the same scripts for server side validations as well (wow! Rhino!).

The Language

Douglas Crockford notes that
... JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java. It has arrays instead of lists and objects instead of property lists. Functions are first class. It has closures. You get lambdas without having to balance all those parens.

all the spices to spruce up your lambdas and closures ..

Erik Kidd is working up to a Ruby esque metaprogramming library for Javascript including porting of RSpec, and Steve Yeggey has butchered Rails into Rhino. Prototype has added lots of Ruby features into Javascript, which are now being used as the base to implement ActiveRecord like features in TrimPath. After a two year hibernation, it is good to hear that TrimPath is being defrosted. With TrimQuery, you can write the following query on the client side for structured Javascript data records ..


// First we precompile the query language object with the schema...
var queryLang = TrimPath.makeQueryLang(columnDefs);

// Next, we do a SELECT statement.
var statement = queryLang.parseSQL(
    "SELECT Customer.id, Customer.acctBalance, Invoice.total " +
        "FROM Customer, Invoice " +
        "WHERE Customer.id = Invoice.custId " +
        "ORDER BY Customer.id ASC");

// Here we run the query...
var results = statement.filter(tableData);
//..



And none of the above is strictly about the Web - there is a growing community enriching the usage of Javascript as a language.

Google Gears - another reason to learn Javascript

Talking about client side persistence, Gears offers a framework for creation of offline browser applications with an embedded SQLite relational database system. Gears offers Javascript APIs for creation of databases, manipulating data and processing resultsets.


var result = db.execute(
    "SELECT * FROM persons"
);
var fieldCount = result.fieldCount();
while(result.isValidRow()){
    for(var i = 0; i < fieldCount; i++){
        var value = result.field(i);
    }
    result.next();
}
result.close();



And Gears is a framework which works offline without the server connection - it is meant to develop applications for the browser, not only for the Web. The rich set of Javascript APIs allows us to build client side persistence on top of a database service. Javascript is no longer the lingua franca for the Web only - it is turning out to be a rich platform for client applications in offline browsers as well. In the server side, as well, Javascript is making an emphatic comeback. Projects like Helma is an ample testimony towards this. For more news on advancement of Javascript as a language, have a look at this document.

Is the browser going to be the next ubiquitous computing platform ? I need to do a lot of catching up ..

1 comment:

Blago said...

I've tried TrimQuery: it's pretty buggy. Especially when you do inserts that contain strings. I wish someone had told me this before I decided to use it for my last project.

In fact, there were so many problems, that in a desperate attempt to save the project I ended up base64 encoding all of my strings (yes, I used "prepared" statements, but this was still trowing it off), then replacing "=" signs. Of course, profiling showed that 75%-80% of the total running time is spent in string conversion.

My advice is, play with it first...

P.S. BTW, the community is non-existent. Don't count on any help. I myself will try Google Gears.