06 Sep 2013, 07:22

Node.js vs Go

Following on from my previous post on Go I thought I’d write some thoughts down on why I think Go has an edge over its competitors, in particular Node.js

I’m not so interested in raw performance comparisons, as for many if not most real-world use cases these metrics are not particularly relevant. What interests me more are aspects such as developer productivity, code maintainability, scalability

For several years now, Node.js has been filling the role of a low barrier for entry tool for rapid development of networking apps. It is well documented and has good cross-platform support. Being built on Javascript has made it accessible and provided a bridge from the front end devs to explore the world of backend systems programming. It’s been wildly popular and I for one have thoroughly enjoyed the ride, however I do think Node.js has peaked.

I’ve written several non-trivial apps in Node.js and while I found it fun and interesting, I can’t bring myself to have a great deal of confidence in the finished product. It just feels unsafe. Javascript is a pretty gnarly language, carrying a lot of baggage from years of being pulled this way and that. Combine that with the async programming model which has a tendency to get you mentally tied up in knots, and it just seems like unexpected behaviour will be the inevitable outcome. Debugging Node.js can be a bitch. It is also very easy to write code that you come back to in 6mths and struggle to figure out what it’s meant to do. It may be possible to avoid these pitfalls, but the fact that they exist at all and bite most people at least a few times, is a sign of a more fundamental problem.

On the topic of scalability, Node.js is tied to a single threaded event loop. This is fine when you have a lot of IO wait and can hop between concurrent tasks, but as soon as you hit a task that chews CPU, all other tasks effectively stop dead. The solution is to spread the tasks across multiple Node.js instances, and that means forking. Setting up and tearing down a new process carries a not insignificant overhead penalty, and so is better suited to a few long-running processes than many short-lived processes. Load balancing of shared socket resource - for example, incoming TCP port connections - is done by the OS in a round-robin fashion; while probably fine for most scenarios, is a limitation none-the-less. To summarize: Node.js can be made to scale, however it requires careful planning and potentially quite a bit of extra overhead in terms of lines of code and system resources.

I feel that Go solves these problems while, importantly, remaining accessible and approachable for both newcomers and old-hands looking for a fresh approach.