Tejas Manohar


Pitfalls of Node.js

Lately, I’ve been writing lots of Python and Go, but if you know anything about me, you’d know I was once a major Node.js advocate. Recently, when I’ve had to stretch my fingers to write a quick “life hack” or number crunching script to speed up my day, I haven’t been thinking of JS, so I definitely can’t call it my go-to language anymore. That said, since I once did, I believe I have the right to criticize it… so, let’s get started.

Standard Library

Node’s standard library is as minimal as can be. Though this is a great way to encourage the community to build libraries, it also makes it harder to standardize and further, compose anything.

But, don’t get me wrong- after working in Ruby and Python, I’m strongly against vast, deep standard libraries. Instead, I prefer standard libraries like that of Go and Java that are vast yet shallow. The difference is these standard libraries provide all the tools you need to solve the most common case and bindings needed to expand beyond, whereas Node’s standard library only provides all the (mostly native) bindings needed to build the tools to solve the most common case. Instead of yet another HTTP client, we develop ways to enhance the standard implementation in a way that’s reusable practically everywhere.

Error Handling

Joyent post on “Error Handling in Node.js”

If the above snippet isn’t enough, take a peek at the following:

function onError(err) {
code: 1,
}, 'process exit');
process.on('unhandledException', onError);
process.on('unhandledRejection', (p, err) => onError(err));

Exception bubbling lets errors that should be handled at call-site propagate endlessly instead, and catch-all handlers are just a workaround for poor language constructs. It’s much harder to realize the impact of your changes when the control flow of an nth degree call-site of a crucial function can affect the overall error handling scene without notice. More importantly, subclass-able Errors promote asserting errors for type, not behavior.

Synchronous Code

Though async I/O is important, it’s not everything. If anything, I’d say forgetting this is Node’s biggest downside by far. Node forces you to think about concurrency everywhere, whereas Go, Lua, Python (though there are other problems there), and other languages allow you to incorporate it in as needed without switching paradigms.

To clarify, you can — and I like to believe that I have — achieved this in Node with newer constructs like generator-based coroutines and Async/Await, but they’re never first-class, and they require loads of tribal knowledge in order to effectively utilize amongst all the other paradigms the community follows. If you don’t believe me, try teaching all this from scratch.

And Beyond!

Now, I’m not saying Node.js is an awful platform; I’m just saying give other platforms a shot and see how things compare! When I was stuck in Node land, I’d often assess other platforms by staring at examples and laughing along, and I’ve seen a lot of (but not all!) fellow JavaScript developers do the same, but, by stepping out of my comfort zone, I’ve learned that it’s impossible to effectively criticize something without developing a strong relationship with it, which for languages, includes debugging, working around abnormalities, and learning ins and outs.

What I’m really trying to point out here is some of the trade-offs that come with Node.js and what I’m excited to see more of built in and moreover, on top of (specifically in terms of tooling) other platforms.

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising &sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!

More by Tejas Manohar

Topics of interest

More Related Stories