Leaving node.js land
I’ve been fighting with Node.js long enough in production now that I don’t enjoy working with it anymore unfortunately, so at least for now this my formal farewell! And more importantly I need maintainers!
Node does some things well, but ultimately it’s not the right tool for the type of software I’m interested in these days. I still plan on using Node for web sites, but if you’re interested in maintaining anything let me know. Just leave a note with your GitHub username, NPM username, and project(s)! As usually all I ask is that you don’t drastically change existing APIs, if you’re doing that then you might as well just start a new project ☺.
Koa is the one project I’ll continue to maintain (along with Co and friends).
The Holy Grail
I’ve always loved C, but anyone who works with C knows that it can be both rewarding and error-prone. It’s hard to justify as the language choice for day-to-day work since it’s not exactly the quickest to work with. The simplicity is something I’ve always admired about it, however without a large amount of boilerplate you won’t get far.
The more I’ve been working with distributed systems, the more I’m frustrated by Node’s direction, which favours performance over usability and robustness. In the past week I’ve rewritten a relatively large distributed system in Go, and it’s robust, performs better, it’s easier to maintain, and has better test coverage since synchronous code is generally nicer and simpler to work with.
I’m not saying Go is the holy grail, it’s not perfect, but for the languages that exist today Go is a great solution for me. As more of these “next-generation” languages such as Rust and Julia find their place and mature, I’m sure we’ll have a lot more great solutions.
Personally I’m most excited about Go because of its iteration speed, it’s exciting to see that they’re eager to reach 2.0 and from what I hear, they’re not too afraid to start breaking things already which is great.
EDIT: I must have misread some mailing list posts, they’re not eager to make breaking changes any time soon. Via @enneff
I would love if this were true, mostly because I believe in breaking things fast if it really benefits the language, but I’m also not a software giant running massive systems :D
Node is still a nice tool and if it’s working for you then you have nothing to worry about, but if things are bothering you, don’t forget to step out of your box and see what else is out there — within the first few hours of using Go for production work I was already hooked.
Again — I’m not saying Go is the absolute best language out there and that you must use it, but it’s very mature and robust for its age (roughly the same age as Node), refactoring with types is pleasant and simple, the tooling Go provides for profiling and debugging is great, and the community has very strong conventions regarding documentation, formatting, benchmarking, and API design.
The Go stdlib is something I thought was awful when I first heard of Go, being so used to ultra-modularity in Node, and having experienced most of Ruby’s stdlib rot. After getting into the language I realized that most of the stdlib is pretty essential to programs these days, compression, json, IO, buffered IO, string manipulation and so on. The bulk of these APIs are well-defined, and powerful. It’s pretty easy to get by writing entire programs with nearly only consuming the stdlib.
Third-party Go packages
There’s no central registry for Go packages, so you’ll often see 5 or 6 packages of the same name. This can be a little confusing at times but it has an interesting side-effect, you really have to review each one to determine the best solution. With Node there are usually canonical packages such as “redis”, “mongodb-native”, or “zeromq”, so you may stop right there and just assume those are the best ones.
Go versus Node
If you’re doing distributed work then you’ll find Go’s expressive concurrency primitives very helpful. We could achieve similar things in Node with generators, but in my opinion generators will only ever get us half way there. Without separate stacks error handling & reporting will be mediocre at best. I also don’t want to wait 3 years for the community to defragment, when we have solutions that work now, and work well.
Error-handling in Go is superior in my opinion. Node is great in the sense that you have to think about every error, and decide what to do. Node fails however because:
- you may get duplicate callbacks
- you may not get a callback at all (lost in limbo)
- you may get out-of-band errors
- emitters may get multiple “error” events
- missing “error” events sends everything to hell
- often unsure what requires “error” handlers
- “error” handlers are very verbose
- callbacks suck
In Go when my code is done, it’s done, you can’t get re-execute the statement. This is not true in Node, you could think a routine is completely finished, until a library accidentally invokes a callback multiple times, or doesn’t properly clear handlers, and cause code to re-execute. This is incredibly difficult to reason about in live production code, why bother? Other languages don’t make you go through this pain.
Personally I think it makes more sense for young startups to focus on reliability over raw performance, that’s what makes or breaks your relationship with customers. This is especially true with small teams, if you’re too busy patching brittle code then you can’t work on the real product.
I still hope Node does well, lots of people have heavily invested in it, and it does have potential. I think Joyent and team need to focus on usability — performance means nothing if your application is frail, difficult to debug, refactor and develop.
The fact that 4-5 years in we still have vague errors such as “Error: getaddrinfo EADDRINFO” is telling of where the priorities are at. Understandably it’s easy to miss things like that when you’re so focused on building out the core of a system, but I think users have expressed this sort of thing over and over, and we’re not seeing results. We usually get poor responses advocating that what we have is perfect, when in practice it’s anything but.
Streams are broken, callbacks are not great to work with, errors are vague, tooling is not great, community convention is sort of there, but lacking compared to Go. That being said there are certain tasks which I would probably still use Node for, building web sites, maybe the odd API or prototype. If Node can fix some of its fundamental problems then it has good chance at remaining relevant, but the performance over usability argument doesn’t fly when another solution is both more performant and more user-friendly.
If the Node community decides to embrace generators and can implement them to the very core of node, to propagate errors properly then there’s a chance that it would be comparable in that area. This would drastically improve Node’s usability and robustness.
The good news here is that I’ve chatted with the awesome & talented guys at StrongLoop a while back who have contributed to core for quite a long time. They’re definitely taking the right approach by listening to developer feedback for the platform, and plan on finding ways to fix its issues and make it more enjoyable to work with for future versions of Node. I’m not sure how the contention between multiple companies working on core will end up, but I hope the developer-driven aspect wins out.
This is not meant to be a personal attack on anyone, lots of really talented people work with, and on Node, but it’s not something I’m interested in anymore. I’ve had a great time being part of the community and got to meet some really cool people.
Moral of the story, don’t get stuck in your own bubble! See what else is out there, you just might enjoy programming again. There are a lot of awesome solutions out there, my mistake was waiting too long to play around with them!☺.