I'm pretty open when it comes to trying out new technologies and I don't really prescribe particularly to technology and language bashing either. I believe in the “right tool for the job” mentality. Over the last 8 months, I've been deep in writing a commercial Node.js application so I'd like to think that I can now at least hold an opinion on it.
I'm really interested to know if you all hold the same or different beliefs or have noticed some of the same issues with Node.js that I'm going to point out in this article. I'm traditionally a Java developer of nearly 10 years so I may be coming from a rose-tinted glasses perspective - so forgive me if you think that's the case.
First off, let's start with Error Handling. Error handling, for me is pretty important for mission critical server-side applications. Java is great in that respect because it provides you with a very solid exception handling model. Even if you don't happen to catch an exception all it'll do is fail your request, it won't completely crash your app. Exceptions are bubbled up the stack and spit out into your console. I like this model. For me it works and it's pretty solid and fairly idiot proof.
Node.js on the other hand, because it's a single threaded model, will bite you hard if you don't pay attention. Woe betide you if you happen to forget to catch an exception. Your absolutely critical Node.js app will crash if you don't handle it, but you can always keep the app running by spinning up a new app in a new node.js thread.
This for me is fairly unforgiveable for a language that you may want to build mission-critical apps with.
I once had a very subtle issue where I was seeing an
undefined:undefined error message in the console after running some tests. No stack trace, just the above error message. My first thoughts. What the hell? Since when could you get an
undefined:undefined rather than an error message and stack trace.
It actually turned out that the error object was actually a string because someone had written...
return 'this new error message'
So what they'd intended was to add additional text to an error thrown further up the call stack so becoming...
new Error('Initial error: this new error message')
This wasn't initially spotted because there was a disconnect between two modules (a common one and one that consumed the common module).
Again, as Java developers we're pretty spoiled here. Maven, for all the stick it gets for “downloading the internet”, is a fantastic dependency management and build tool. There's also Gradle as well which again is really really great. Both are very mature and “Just Work”TM.
NPM on the other-hand is a terrible dependency management tool. It's great when it works but when it doesn't you often get incomprehensible errors and stack traces. Googling npm errors often leads to Github issue tickets where problems are brushed off and an npm cache clean or removal of the
node_modules folder is suggested followed by an
I've found that because of a distinct lack of a decent debugging toolset for the Node.js stack I use console.log a lot more than I feel I should. I actually can't remember the last time I had to log out stuff in Java because the debugging tools are just so darn good.
This irritates me no end. It feels very much like a backwards step in my eyes.
Lack of Type Safety when using Foreign APIs
In the Node.js world you'll find that you tend to consume lots of different libraries etc. because Node.js really doesn't provide you with that much out of the box. Looking at API documentation for modules is therefore a must.
Due to the lack of typing and the fact that debugging tools are not great making use of new libraries can be a source of extreme frustration, especially when the documentation for said library is woefully lacking.
Now I love the concept of Promises, however, writing tests for promisified code is painful. You need to ensure you always resolve your promises before you can make any assertions about the correctness of your code. Not to mention on top of that you can have callback hell with having to close your callbacks correctly for cucumber or jasmine unit test suites.
In Java, you don't have to worry about any of those problems any more. Sure, concurrent code can be complex but often you have frameworks (such as Apache Camel that are excellent at abstracting away that complexity and letting you deal just with the business logic. Also, with the recent advancement of Akka and more recently the Quasar framework this job has been made significantly easier.
Do we really have need of the ubiquitous use of Promises any more when we have multi-threaded languages and such frameworks at our disposal?
Which NPM library do we use? No Idea?!
The Node.js community for me is very fragmented. It's difficult to know which NPM library is best to use with an option of at least a dozen at your disposal. Also, even if you happen to find a library that's used by 98% of the projects out there you take a look under the hood and you might be horrified. One particularly well known and core library I found had an entrance method that was full of if statements and the method was 600 lines long! I would absolutely not like to have to maintain that.
var self = this;
Both of which means your code is in essence much less readable. I would definitely sacrifice performance for readability and maintainability any day of the week.
From my perspective, I would much rather just deal with the stack in a single language only since it's much more predictable and there's less margin for error.
OO or Functional?
An ability to use flexible prototypal inheritence and also use a functional style of programming. More often than not though I've found that the Object Oriented paradigm has been dropped completely in Node.js applications in favour of a procedural approach. For me, OO, procedural and functional programming paradigms should be married together and used when appropriate. Node.js doesn't seem to encourage this as much and has a heavy procedural bias.
Io.js / Node.js
Ten Ways to Solve the Same Problem
As a Node.js developer you'll notice that there are so many ways to skin a cat it becomes almost impossible to choose. Go onto Stack Overflow and you'll receive lots of different answers to the same question. Sometimes choice is good but I actually prefer the structured rules as they enable you to be more productive because you don't have to make these choices (they're made for you!).
Google Searches don't bear Fruit
I've found that many Google searches are often very unfruitful as far as turning up answers is concerned and that it can often take 6-7 posts/links before you find a solution close to what you're after. I'm not sure why this in comparison with Java but it seems a lot harder to find the answers to your problems via keywords in Js than with other languages.
Just a trend?
A cynical part of me thinks that the current trend with Node.js is part of the “full-stack” developer trendy movement, but as I stated earlier in the post I'm a “right tool for the right job” kind of guy and whilst it's not cool any more to code in Java it's a pretty solid choice to get things done.
I think as a community we need to take more responsibility as far as adopting new languages and platforms is concerned and not be so quick and eager to jump onto the “next big thing” just because some big corporation or other has decided to adopt it. It may not be the right choice for us.
I hope you've enjoyed this article and I really welcome good debate. How have you found Node.js? Do my hopes and fears ring true with you?
UPDATE: 25th August 2016
I can't stress enough that if there's anything to take away from this blog post I would say it would be around the increased importance of monitoring and logging when building applications in Node.js
I would still advocate the use of Node in certain circumstances. It's excellent for example as a backbone for applications that require a lot of short-running threads. So if your application design leverages and makes best use of that, then by all means Node is a great solution.
However, it doesn't suit monolithic architectures.
If you're going to use Node make sure the purpose of it is well-defined and you're designing for scalability with lots of async processing. So don't go doing something stupid like trying to use a single-threaded non-blocking framework like Node for long running calculations or data analytics. Leave that to Java, Scala, Go or some other more heavyweight multi-threaded language.