Tue, 1 May 2012
By Thomas ten Cate
- Immaturity. Often, there are five different Node.js libraries that do approximately the same thing, but all of them are buggy and none do it exactly the way you’d want.
- Documentation. Nonexistent for most Node.js modules; most just provide one or two canonical usage examples. You could argue that I should simply read the source, but that is often difficult if you don’t have the high-level picture of how things fit together.
- Callback spaghetti. For instance, the way I’m importing a word list into the MongoDB database backend takes no less than seven levels of nested callbacks: create database connection, open database, drop collection, create collection, open file, read lines, insert data. When done reading, open other collection, update word count. When written like this it looks straightforward, but in code, each action is a new level of nested callbacks. There are libraries like flow.js that make this a little easier, but they mostly remove indentation levels while not fundamentally changing anything. I like to write event-driven code when it makes sense, but being forced to use it for everything is a pain.
- Difficulty of event-driven programming. It gets really difficult to tell what gets executed when. For instance, I had a bug where I opened a file and wanted to read it line-by-line in an event-driven way. I knew how many lines the file had, but the code consistently kept reading fewer lines than that. The cause? After verifying that the file existed by having opened it successfully, I opened a database connection. But while doing so, my file object already started streaming out read events, even though no event handler had been hooked up to it yet! This caused the first few thousand lines of the file to be ignored. As the event handler needed an open database, there was no way to hook it up earlier. The “fix” was to open the database first, then open the file and synchronously hook up the data event handler.
var i;at the top of the function if I use
ias a counter in a
forloop, K&R C-style. Some such nonsense can be turned off, but not all. JSHint is better in this respect, but has other problems. Both struggle with unrecognized global variables that Node.js provides.
- Syntax. It matters. Too many
functionobjects make me go dizzy.
I’m planning to use Sinatra for serving static files, and Cramp (built on top of EventMachine) for the game logic. This will still be event-driven code, but only where it makes sense, and hopefully Ruby syntax will make it more pleasant to use. Cramp supports WebSockets out of the box, assuming one uses Thin or Rainbows as the HTTP server.
For older browsers, I might use the Flash fallback of web-sockets-js, or I could use socket.io-ruby. But as I don’t like Socket.IO very much either (feature creep, bad documentation, and new bugs every release), it’ll probably be the former. There won’t be a “polling” fallback for browsers that support neither WebSockets nor Flash, but I think I can live with that.