What’s wrong with Node.js and Javascript?

So in my last post I promised to talk about what is wrong with Node.js and Javascript.

Let’s start with Javascript…

One big issue is that the OO model seems to be a bit fragile. It is instance based rather than class based, so objects have methods which they simply gather up from the “prototype” when you construct them. Or something like that. It’s all a bit unclear to me exactly how it all works, and inheritance is fragile – you can’t change an object’s inheritance after putting methods in the prototype already, as that resets the prototype. To be honest this isn’t *that* much worse than Perl, but then I am not holding Perl up as the greatest OO language to compare to. On the plus side people have created conventions for making this work reasonably cleanly, and some code can look pretty decent.

At first I was annoyed that strings are immutable. This comes across as slightly weird sometimes because there are operators which make them look mutable such as “+=” to append to a string, but really that just gives you a new string behind the scenes – it’s just syntactic sugar. I’m kind of used to this now.

Regular expressions suck. They have no “s” modifier to allow a dot to match any char (you have to use [\s\S]). Lots and lots of things in regexps are not supported. At some point I’ll probably have to do an interface to re2 or pcre to access what I need. On the other hand the interface is nicer than Perl’s “Global Variables” approach when accessing matched text.

There’s no way to have binary strings. This is super frustrating. If you are dealing with a line-based protocol like SMTP which might not be 7bit clean, there’s just no way to have both regexps (to handle the line-at-a-time code) and binary data. I’d have to iterate over the “Buffer” (which is how you do binary data in Node.js) a character at a time to find the line endings, and I doubt that would perform (though in fairness I haven’t tried it).

There’s inconsistencies. For example you can do: for (var i = 0; i < 10; i++) { ... } but you can’t do if (var m = str.match(/t/)) { ... } (what I’m pointing out is the lexically defined “var” there).

There’s no easy way to get line numbers of callers (well there is, but you have to construct a new Error(), which feels odd). I suspect this is due to the browser heritage – a bit of a security through obscurity thing.

In general the language feels a bit “light” on features. Again this is because of the browser heritage, and lots is being added through modules.

Now onto Node.js…

The biggest problem really is the immaturity of the libraries. There’s just a lot missing that you might expect, especially for something that is designed for writing servers.

Typical examples:

  • There’s no file locking (flock) available. This is utterly dumbfounding.
  • There’s no setsid() and no fork(), so without an external library you can’t daemonise.
  • There’s no way to set socket options, you have to rely on what the API already provides you with.
  • There’s no seek() or a way to seek() on a file, and no way to reset the EOF counter.

You get the idea – the library is just young and naive.

The other problem which has me rather concerned is the lack of API stability – there’s no deprecation cycle yet in their project management, things just get ripped out if they are deemed “bad”. One example was socket.setSecure() (upgrade a socket to TLS), which I could really use, and see no reason it’s a “bad” API. I suspect it was broken in some ways and was just too hard to fix. Apparently there’s a way for me to still emulate socket.setSecure() but I can’t for the life of me figure it out with the current APIs in place.

The event loop… Having it is great, but if you block (say you need to build a large data structure) you’re screwed. There’s no threads or way to build it outside of the event loop aside from a worker and sending the structure back as JSON (but then you have to parse THAT!). There’s a lot of zealotry in the node community that their way is just fine and that you shouldn’t ever need to do this, but sadly it’s not true.

Finally one more thing: There’s no decent line profiler yet. I don’t even know if this can be built without hooking into the debugger. Basically something like NYTProf would be great. There’s some subroutine level profiling built into v8, but I can’t figure it out.

I’m sure I have other gripes, but those are the major ones I can remember.


Why Node.js?

In the last few weeks I have built from scratch a new SMTP server (based loosely on the concepts in Qpsmtpd) using Node.JS. A number of people have asked me why, so I thought I would create a blog and start writing about it.

The main reason really was to just learn something new. I’ve been coding mostly in perl now for 15 years, and while I still appreciate the language, the rough edges do start to wear on you. A few years ago I decided that new thing would be Ruby, but the performance of the language just wasn’t there, and so I gave up. I tried Python for a while, but didn’t like it either. I had coded in Java before, and so I knew that wasn’t what I wanted.

What sparked my interest in using Javascript was reading about the performance of Google’s V8 engine. It appears to have taken all of the scripting performance expertise developed in the lisp and smalltalk arenas and implemented them in a very fast Javascript engine. Great for the browser, but equally nice to have on the server.

The other thing that really got me interested is that I’ve been programming async-IO systems in Perl for a while now, and the major problem I find there is that none of the other perl coders are used to writing async systems, and so all the libraries out there are synchronous. This is a real problem if you plug those into an asynchronous system because it blocks the event loop.

With Node.JS everyone is coding async libraries, because the core libraries are asynchronous, and so everyone just expects it to work that way. Genius!

So I got cracking with some coding, figured out how the weird and slightly fragile OO system works, and came up with Haraka.

What I am really enjoying about hacking on this (rather than Qpsmtpd for example) is I have some really solid plans from the start of how I want monitoring, configuration, etc to work across a cluster of mail servers, rather than just an individual server. This will at some point (it hasn’t yet, but it’s early days) influence my design. One way we’re seeing this right now is very early on I have implemented a web-based graph built-in to it which shows you which plugins rejected your mail. I hope to advance that some day to include a full breakdown on things like which DNSBL rejected your mail, which will be very sweet indeed. And then maybe at some point even have it going down to the individual domain and recipient level… Oh that would rock.


Haraka Test graphs (note this is just a mock up, not real data)

So how is performance? Well so far it looks pretty good. I can process and save to disk about 5000 mails/sec on my iMac. I’m not sure yet how that stacks up to other mail servers (even Qpsmtpd) but I’m willing to bet it’s not bad.

Next post: The weaknesses of Node.JS and Javascript in general.