Saturday, September 22, 2007

Compiled Javascript and HTTP Accept

I've been thinking about the future of Javascript and Javascript performance and scalability lately. Joel Spolsky mentions that the future is a programming language which compiles to Javascript (several projects already in progress, by the way).

My vision of the future is serving pre-compiled, cached Javascript directly to clients. Firefox plans to use the Tamarin Javascript engine to run Javascript inside the browser. Why not just send precompiled Tamarin bytecode downstream. A web browser simply requests foo.js with an HTTP Accept header something like Accept: application/tamarin, text/javascript; q=0.8 The server compiles foo.js, caches the result for future requests and sends the bytecode downstream. This reduces the download size and speeds up client behavior. If a browser doesn't understand pre-compiled Tamarin bytecode, it'll just get the straight Javascript like before.

If this happens, it doesn't matter how one generates Javascript or bytecode, it'll be faster to download and run.

Friday, September 7, 2007

Installing JavaScript.pm on OS X

While researching an idea for an HTML form building module, I wanted a way to embed a JavaScript interpreter inside a Perl program. The plan is to execute the same JavaScript code on the client and on the server. The only difference would be the context provided by the browser versus the context provided by the CGI script, respectively.

There are two Perl modules on the CPAN that embed a JavaScript interpreter in Perl: JavaScript and JavaScript::SpiderMonkey. JavaScript::SpiderMonkey looked promising but it depends on the behemoth Log::Log4perl and the build arrangement didn't seem as upgradeable as JavaScript's.

Installation was pretty straightforward. Initially I tried a simple cpan JavaScript which didn't work since I had no installation of SpiderMonkey. This incantation did the trick:

sudo port install spidermonkey
export JS_LIB=/opt/local/lib
export JS_INC=/opt/local/include/js:/opt/local/include/nspr
cpan JavaScript
   * answer Y to threadsafe
   * answer N to unicode
   * answer N to E4X

Saturday, September 1, 2007

Unit Testing of C Libraries

I wasn't happy with any of the exsiting time tracking applications available, so I've been developing my own time tracker. I hacked together the early prototype in Perl and it works quite well. However, to increase the start-up speed and hone my C skills, I've started rewriting portions in C.

Writing unit tests is a good idea in any language. My first attempt was to write unit tests for my new C functions by writing small C programs which used those functions. That was painful to develop and didn't give me all the nice features of Perl tests that I'm accustomed to. Then I remembered something I'd read in the great book Perl Testing. With a bit of Perl code, one can use Perl's testing tools to test C functions. I've compiled my C functions into a library called libtimeline so this Perl code is all I need:

use strict;
use warnings;
use Test::More tests => 1;

use Inline
    C      => 'const char *timeline_default_filename();',
    ENABLE => 'AUTOWRAP',
    LIBS   => '-L/Users/michael/src/clk -ltimeline',
;

is( timeline_default_filename(), '/Users/michael/.clk/timeline' );
# more tests ...

I wrote a wrapper around most of that, so all I do now is something like this:

use strict;
use warnings;
use Test::More tests => 1;
use App::Clk::TestC;

App::Clk::TestC->function('timeline_default_filename');
is( timeline_default_filename(), '/Users/michael/.clk/timeline' );
# more tests ...

When I was first trying to get this working, I kept getting error messages like:

Use of inherited AUTOLOAD for non-method main::timeline_default_filename() is deprecated
Can't locate auto/main/timeline_de.al in @INC

My first error was that I had typed the C function name incorrectly in the prototype. After I corrected that, I got the same error again. This time it was because my prototype had const char *timeline_default_filename(void) but apparently Inline::C doesn't understand void. Once I changed the prototype to const char *timeline_default_filename() it worked fine.

Deploying Perl Applications

For two clients, I develop reporting tools which run under Windows. Eventhough both clients have technically knowledgable staff, installing the Perl application I've written for them has often caused headaches. The trouble comes when installing additional Perl modules. ActiveState Perl's ppm tool makes module installation relatively simple, but there were often problems anyway. Neither I nor my clients want to waste time on module installation.

A few days ago, I discovered PerlApp (part of ActiveState's Perl Dev Kit). It lets me package my Perl apps into a single Windows executable. I send my client the .exe, they save it on their local machine and double-click. That's it. All the module dependencies are bundled inside. PerlApp even lets me bundle external configuration and data files into the executable.

I could have used the Perl Archive Toolkit (which is free), but the extra effort isn't worth the lower cost. I'm pretty sure that PerlApp uses PAR internally, but I'm glad to pay ActiveState for polishing off PAR's rough edges.