Exploring a new frontier

yummy coffee

Beginning a few years ago, there have been a few projects – Rhino, Jaxer, more recently Narwhal – that proclaimed we were about to enter a golden era of server-side JavaScript programming. But the implementations always seemed to fall a bit short of expectations, and none of those projects have yet managed to generate the kind of attention and enthusiasm one might hope to see.

But then lately, and for the last few months, I've been hearing really good things about Node.js and when I saw this blog post I decided to give Node.js a shot.

But: first a little background.

My latest project at work involves wrangling a sprawling horde of almost entirely arbitrary metadata. I've been really impressed with MongoDB's combination of traditional relational-database and new-fangled "document-oriented" features, but there's been a problem.

Ruby.

Well… kinda. Mostly. Basically.

There are a handful of MongoDB adapters for Ruby and/or Rails; my favorite tends to be MongoMapper. Except that, MongoMapper requires the developer to explicitly declare the model's attributes (ala DataMapper, MongoMapper's namesake) which, kinda, basically, mostly defeats the flexibility advantages of using something like Mongo in the first place.

There is also Candy which maintains most of Mongo's flexibility, but: 1) it doesn't "feel" like idiomatic Ruby (it diverges wildly from standard-bearer ActiveRecord, at least) and 2) it uses (painfully slow) method-missing "deep magic" to dynamically read and write from arbitrary attributes.

But also: I've been thinking that I might end up using something like Cappuccino as the front-end framework. In which case, I'd kind of like to just get the JSON that's coming out of Mongo, more or less unmolested, and let the fancy Objective-J client do the processing. For this particularly project, it started to feel that Ruby's obsession with object-relationship mapping was actively getting in the way.

And then sometime last week, I stumbled upon this tutorial by Ciaran Jessup that walks through creating a simple blog application (why do new web frameworks always start with blog tutorials?), written in Node.js, with database-backing provided by MongoDB.

His tutorial uses Express, a Node-powered http server that closely mirrors Ruby's Sinatra. This is where things start to feel familiar: I know my way around Sinatra, and I already tend to think Sinatra is a great "middle layer" for Cappuccino front-ends.

So: for the last few days, I've been hacking away on a little "proof of concept" project (you can follow along on github here), a "custom blend" of two tutorials: Ciaran's Node/Express/Mongo tutorial and this series on CappuccinoCasts about building a blog app backed by Rails.

The Cappuccino app is least changed from what's in the screencast, except that I threw in some bits working in Atlas (from a later episode), and had to figure out how to adjust Cappuccino's load paths to launch from the "static files" part of the Express app. (I'm a little disappointed in Atlas – for a "pay to play" beta, I expected something a little less buggy.)

My contributions here involved expanding Ciaran's very basic blog app to provide a few RESTful endpoints, and expanding his minimalistic Mongo-wrapper to also provide delete and update features. To make matters a little more challenging, I decided that I wanted to try writing the Express app in CoffeeScript – a variant, nicer syntax for JavaScript, that can be compiled into JavaScript.

Although CoffeeScript is easier to read and write than traditional JavaScript – borrowing good bits from both Ruby and Python, while still preserving the essential "javascriptiness" – I've never really warmed to the idea of writing for the browser in CoffeeScript, as it would seem to require some frequent re-compiling during development — true, there are resources available that help make that easier, it's just never appealed to me. But I'm much less cautious of writing server-side code that way.

So, how was it?

Well, first the good news: Node.js is fast. Insanely, unbelievably fast. Maybe this just tells you that I've spent too much time working with Ruby, but I found it astonishing. Posting a comment on the blog happens so quickly, I initially assumed it wasn't working — I thought, "it can't have done that so fast, there must be an error or something".

So, Express works reasonably well as a JSONified RESTful back-end for Cappuccino, with none of the "Mongo-in-a-straight-jacket" feeling I had with Ruby. And I think CoffeeScript is an instant "hit" – if one is already reasonably familiar with JavaScript, as well as at least one of Ruby or Python.

But it wasn't all cotton candy and rainbows…

First, as familiar as I am with JavaScript, after a decade or more time writing it for browsers, it's almost like learning a new language again. The server-side context is sufficiently different as to require a substantial shift in perspective ("you mean I don't have to walk the DOM?"), and a new raft of tools (there are multiple, actively competing package managers for server-side JavaScript) to familiarize oneself with. I'd like to find something like Ruby's irb (ie, a REPL for Node), to help explore the language in an interactive environment, with more immediate feedback.

Second, there's a lot of moving pieces: in addition to my code, there's CoffeeScript compiling syntaxes, Express setting up listeners and routing, and Node.js executing all that comes out. With all that's going on "under the covers", the "javascript stack" can be a little wobbly. I remember running into similar problems in the early days with Rails' long, confusing stack traces being more than a little overwhelming.

Some examples of places where this bit me:

  • At one point, I was flummoxed by a "syntax error" from coffee, that turned out to be an unknown-to-me JavaScript reserved word — blindly assuming that "delete" routes worked in Express as they do in Sinatra, when "delete" in JavaScript nullifies properties on objects. (Express uses "del" instead of "delete".)
  • Or, reading the stack trace from an error involving Express' "render" method, it looked to me that there were problems finding the specified template, but it turned out that Express was also trying to find a layout template (which had yet to be created), and failing loudly when it couldn't be located. (You can explicitly turn layouts off, but I had assumed it wouldn't require one anyway.)

Ultimately, Node.js and/or Express (realistically: and/or Coffee) might still be just a little too unstable. I found that small errors (sometimes including badly-formed JSON strings) could crash the entire server. Sure, some of that is my fault – bad code is bad code, afterall – and I know I can bring down a Ruby server, too, but it happened a bit more often than I'd like. I'm sure this will get better as Node and Express evolve, but for now, there's a tutorial available here on using Monit to keep Node alive.

Given that it's still "early days" (both Node and Express are pre-version 1.0), all of this is understandable, and things will only improve from here. After a few years with Ruby, it seems like the "JavaScript guys" are approaching web development programming in reverse – build a super-fast server first, then follow up with a minimalist "framework", and throw in some (optional) pretty syntax on top – and I mean that in a good way. Approaching things this way seems to have resulted in something that's wicked fast, today – and that's a great foundation to build on going forward.

Permalink • Posted in: javascript, programming, webComments (3)

Comments

Kieran Huggins Apr 27, 2010

Javascript's reserved words have tripped me up more than a few times as well... especially as property names, which I find particularly annoying since it's not like there's any chance of ambiguity.

I dig express/sinatra for smaller apps, but for larger projects Geddy looks really promising. Geddy feels like the love-child of Merb and Node, although quite obviously in early alpha (with a capitol alpha).

Pete Forde Apr 28, 2010

This looks promising!

http://github.com/smtlaissezfaire/ndb

Joshua Wehner Apr 29, 2010

@Eelco: Since the app was fairly minimal, I didn't write extensive tests, but I could see the callback architecture adding some additional challenges. That said, I was under the impression that there is a test suite for Node.js, and tend to assume it may have some pointers?

@Kieran: I've only looked a little at Geddy, but my (very brief) initial impression was that it wasn't super-flexible; maybe a bit more Rails than Merb, for better or worse.

@Pete: Thanks - I should check that out!