The emperor’s new clothes were built with Node.js
Wednesday, 4 June 2014
There are plenty of people lambasting Node.js (see the infamous “Node.js is cancer”) but proponents tend to misunderstand the message and come up with irrelevant counterpoints. It’s made worse because there are two very different classes of people that use Node.js. The first kind of people are those who need highly concurrent servers that can handle many connections at once: HTTP proxies, Websocket chat servers, etc. The second are those who are so dependent on JavaScript that they need to use JS across their browser, server, database, and laundry machine.
I want to address one-by-one all of the strange and misguided arguments for Node.js in one place.
Update: Please keep sending in anything I missed! Moderation of comments will probably continue to lag behind, but I do read them and will continue fixing and tightening up this article as best as I can.
TL;DR: what’s clothing that doesn’t use threads and doesn’t block (anything)?
Node.js is fast!
This is actually too imprecise. Let’s break it down into two separate claims:
a. JavaScript running on V8 is fast!
You have to give the V8 developers some kudos. V8 has done incredible things to run JavaScript code really fast. How fast? Anywhere from 1x to 5x times slower than Java, at least for the Benchmarks Game. (Some of you may not realize that “slower” is not a typo.)
If you look at their benchmarks, you’ll notice that V8 ships a really freakin’ good regex engine. Conclusion? Node.js is best suited for CPU-bound regex-heavy workloads.
So if we take the Benchmarks Game to be gospel, then what languages/implementations are typically faster than JavaScript/V8? Oh, just some unproductive ones like Java, Go, Erlang (HiPE), Clojure, C#, F#, Haskell (GHC), OCaml, Lisp (SBCL). Nothing that you could write a web server in.
And it’s good that you don’t need to use multiple cores at once, since the interpreter is single-threaded. (Comments will no doubt point out that you can run multiple processes in Node.js, something that you can’t do with any other language.)
b. Node.js is non-blocking! It has super concurrency! It’s evented!
Sometimes I wonder whether people even understand what they’re saying.
Node.js is in this weird spot where you don’t get the convenience of light-weight threads but you’re manually doing all the work a light-weight threads implementation would do for you. Since JavaScript doesn’t have built-in support for any sort of sane concurrency, what grew out of it was a library of functions that use callbacks. PL folks will realize that it’s just a crappy version of continuation-passing style (Sussman and Steele 1975), but instead of being used to work around recursion growing the stack, it’s used to work around a language without built-in support for concurrency.
So yes, Node.js can effectively deal with many connections in a single-threaded application, but it wasn’t the first or only runtime to do so. Look at Vert.x, Erlang, Stackless Python, GHC, Go…
The best part is all the people jumping through hoops to create their MVP in Node.js because they think it’ll make their site faster for their swarms of future users. (Never mind that loading 500K of Backbone.js code and miscellaneous libraries is not very high performance anyways.)
Node.js makes concurrency easy!
JavaScript doesn’t have built-in language features for concurrency, Node.js doesn’t provide that magic, and there are no metaprogramming capabilities. You have to manage all of your continuations manually, or with the help of (lots of different) libraries that push JavaScript syntax to its absurd limits. (BTW, I find should.js both horrific and convenient.) It’s the modern-day equivalent of using GOTO because your language doesn’t have for loops.
Let’s compare.
In node.js, you might write this function for some business task:
[javascript]
function dostuff(callback) {
task1(function(x) {
task2(x, function(y) {
task3(y, function(z) {
if (z < 0) {
callback(0);
} else {
callback(z);
});
});
});
}
[/javascript]
Clear as mud. Let’s use Q promises instead!
[javascript]
function dostuff() {
return task1()
.then(task2)
.then(task3)
.then(function(z) {
if (z < 0) {
return 0;
} else {
return z;
});
}
[/javascript]
A lot more readable, but still dumb. One side effect is that Q eats your exceptions unless you remember to finish your chain with “.done()”, and there are plenty of other pitfalls that aren’t obvious. Of course, most libraries in Node.js don’t use Q, so you’re still stuck using callbacks anyways. What if task2 didn’t return a Q promise?
[javascript]
function dostuff() {
return task1()
.then(function(x) {
var deferred = Q.defer();
task2(x, deferred.resolve);
return deferred;
})
.then(task3)
.then(function(z) {
if (z < 0) {
return 0;
} else {
return z;
}
})
.done();
}
[/javascript]
The code above is broken. Can you spot why? By the way, we also forgot to handle exceptions. Let’s fix these issues:
[javascript]
function dostuff() {
return task1()
.then(function(x) {
var deferred = Q.defer();
task2(x, function(err, res) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(res);
}
});
return deferred.promise;
},
function(e) {
console.log(“Task 1 failed.”);
})
.then(task3, function(e) {
console.log(“Task 2 failed.”);
})
.then(function(z) {
if (z < 0) {
return 0;
} else {
return z;
}
},
function(e) {
console.log(“Task 3 failed.”);
})
.done();
}
[/javascript]
Notice how the error handling and the tasks they correspond to are interleaved. Are we having fun yet?
In Go, you can write code like this:
[code]
func dostuff() int {
z := task3(task2(task1())))
if z < 0 {
return 0
}
return z
}
[/code]
Or with error handling:
[code]
func dostuff() int, err {
x, err := task1();
if err != nil {
log.Print(“Task 1 failed.”)
return 0, err
}
y, err := task2(x);
if err != nil {
log.Print(“Task 2 failed.”)
return 0, err
}
z, err := task3(y);
if err != nil {
log.Print(“Task 3 failed.”)
return 0, err
}
if z < 0 {
return 0;
}
return z;
}
[/code]
Realize that both the Go and Node.js versions are basically equivalent, except Go handles the yielding and waiting. In Node.js, we have to manage our continuations manually because we have to work against the built-in control flow.
Oh, before you actually do any of this stuff, you have to learn not to release Zalgo, possibly by using synthetic deferrals (say what?) so that you don’t make your API’s users unhappy. In the world of “lean” and MEAN MVPs, who has time to learn about leaky abstractions on top of some obtuse runtime?
By the way, Q is super slow (or so the Internet says). Check out this handy performance guide comparing 21 different ways of handling asynchronous calls!
No wonder people love Node.js. It gives you the same performance as lightweight threads but with the clarity and usability of x86 assembly.
When people point out how unpleasant it is to manually handle control flow in Node.js, the proponents say, “Use libraries to handle that, like async.js!” So you start using library functions to run a list of tasks in parallel or compose two functions, which is exactly what you’d do with any threaded language, except worse.
LinkedIn went from 30 servers to 3 by switching to Node.js!
Quoth Hacker News: “I switched from a dump truck to a motorbike and now I drive a lot faster!”
PayPal and Wal-Mart have also had high-profile switches to Node.js. Of course, they’re comparing two completely different things to make Node.js look better. In these too-good-to-be-true stories, they’re switching from a gigantic enterprisey codebase to a Node.js app written from scratch. Is there any question that it wouldn’t have been faster? They could have switched to pretty much any anything and gotten a performance gain.
In LinkedIn’s case, they had proxies running on Mongrel with a concurrency of 1. It’s like switching from using one finger to type on a QWERTY keyboard to using ten fingers on a Dvorak keyboard and giving all the credit to Dvorak for a better keyboard layout.
This is classic hype: real-world stories misunderstood and twisted to confuse the unwitting.
It lets you leverage your existing JavaScript expertise!
Let’s be more specific and break this down into a couple parts:
a. The frontend devs can work on the backend!
Where was JavaScript used previously? Primarily browser-side front-end code to animate buttons or smoosh JSON into fancy interfaces. By leveraging JavaScript on the backend, you let your ninja UI devs hack on mission-critical networking code. Since it’s JS on both ends, there’s nothing to learn! (Right?)
Wait until they find out that they can’t use return
normally (because concurrency!), they can’t use throw/catch
normally (because concurrency!), and everything they call is callback based, returns a Q promise, returns a native promise, is a generator, is a pipe, or some other weird thing because it’s Node.js. (Just tell them to check the type signatures.)
Have some faith in your frontend devs’ ability to learn a different backend language. Because if a different language for the backend is too big an obstacle, then so is figuring out how to mix and match all the different callbacks/promises/generators into code that doesn’t collapse every time a change is made.
b. We can share code between the backend and frontend!
You’re then limiting your server-side code to use only language features that browsers support. For example, your shared code can’t use JS 1.7 generators until the browsers support it too and we have enough experience to know that adoption could take years.
Effectively, we can’t improve the server language in Node in substantial ways without drifting away from the browser language. Node.js has so many gaping holes that are up to the libraries to fix, but since it’s chained to the language we call JavaScript, it’s can’t strike out on its own to address these things at the language level.
It’s an awkward situation where the language doesn’t give you much, but you can’t change the language so you keep doing npm install band-aid
.
This can be fixed by running some sort of compilation step to transform new language features into older features so you can write for the server and still run on regular JavaScript. Your choices are either something that’s 95% JavaScript (TypeScript, CoffeeScript) or not JavaScript at all (ClojureScript, perhaps).
More worrying is that this argument implies that you actually muddle the concerns of your server and frontend. In the real world, you’ll find that your backend turns into a JSON API that handles all of the validation, processing, etc., and you have multiple (sometimes third-party) consumers of that API. For example, when you decide to build iPhone and Android apps, you’ll have to decide between a native app in Java, Obj-C, or C#, or packing your one-page Backbone.js/Angular.js app using Phonegap/Cordova. The code you share between the server and client may end up being a liability, depending on what platform you go with.
NPM is so great!
I think NPM has attained a status of “not awful”, which puts it ahead of many other package managers. Like most ecosystems, NPM is pretty cluttered with multiple redundant implementations of the same thing. Say you need a library for sending Android push notifications. On NPM, you’ll find: gcm, node-gcm, node-gcm-service, dpush, gcm4node, libgcm, and ngcm, not to mention all the libraries that support multiple notification services. Which are reliable? Which are abandoned? In the end, you just pick the one that has the most downloads (but why can’t we sort results by popularity?).
NPM also has a less-than-stellar operations track record. It used to go down quite often and it was hilarious seeing all the companies that suddenly couldn’t deploy code because NPM was having troubles again. Its up-time is quite a bit better now, but who knows if they will suddenly break your deployment process because they can.
We somehow managed to deploy code in the past without introducing a deploy-time dependency on a young, volunteer-run, created-from-scratch package repository. We even did such blasphemous things as including a copy of the library source locally!
I’m not worried about NPM—in some sense, it’s part of the ecosystem but not the language, and it generally gets the job done.
I’m so productive with Node.js! Agile! Fast! MVP!
There seems to be a weird dichotomy in the minds of Node.js programmers: either you’re running mod_php or some Java EE monstrosity and therefore a dinosaur, or you’re on Node.js and super lean and fast. This might explain why you don’t see as many people bragging about how they went from Python to Node.js.* Certainly, if you come from an over-engineered system where doing anything requires an AbstractFactoryFactorySingletonBean, the lack of structure in Node.js is refreshing. But to say that this makes Node.js more productive is an error of omission—namely, they leave out all the things that suck.
Here’s what a newcomer to Node.js might do:
1. This function might fail and I need to throw an exception, so I’ll write throw new Error("it broke");
.
2. The exception isn’t caught by my try-catch!
3. Using process.on("uncaughtException")
seemed to do it.
4. I’m not getting the stacktrace I expected, and StackOverflow says that this way violates best practices anyways.
5. Maybe if I try using domains?
6. Oh, callbacks typically take the error as the first parameter. I should go back and change my function calls.
7. Someone else told me to use promises instead.
8. After reading the examples ten or twelve times, I think I have it working.
9. Except that it ate my exceptions. Wait, I needed to put .done()
at the end of the chain.
Here’s a Python programmer:
1. raise Exception("it broke");
Here’s a Go programmer:
1. I’ll add err
to my return signature and change my return
statements to add a second return value.
There is a lot of stuff in Node.js that actually gets in the way of producing an MVP. The MVP isn’t where you should be worrying about returning an HTTP response 40ms faster or how many simultaneous connections your DigitalOcean “droplet” can support. You don’t have time to become an expert on concurrency paradigms (and you’re clearly not because you wouldn’t be using Node otherwise!).
* Check out this great post about switching from Python to Node.js. The money quote is, “Specifically, the deferred programming model is difficult for developers to quickly grasp and debug. It tended to be ‘fail’ deadly, in that if a developer didn’t fully understand Twisted Python, they would make many innocent mistakes.” So they switched to another difficult system that fails in subtle ways if you don’t fully understand it and make innocent mistakes!
I love Node.js! Node.js is life!
Does your local Node.js Meetup group need a presenter? I am available for paid speaking engagements. Email me for more info.
These opinions do not represent that of and were not reviewed by my employer or colleagues. Also, feel free to wrap all lines with <sarcasm> tags.
No. 1 — June 6th, 2014 at 14:52
Good article! Nodejs is really productive!
No. 2 — November 2nd, 2017 at 13:35
The article is not well structured. There are 2 topics here that should be covered:
1. The objectives that Node.js was built for and where it fits best and if it does the job well. This is not a general purpose tool, but a specific solution for a specific problem…
2. The limitations of Node.js, where it fails and where it shouldn’t be used, with examples.
Long article, poor structure.
No. 3 — June 6th, 2014 at 14:58
There’s something to be said for a library ecosystem where people know to flag their blocking calls. If you’re writing Python and using twisted for async, it works great – as long as you’re using twisted or twisted-based libraries for everything. As soon as you try and use a library that doesn’t know about twisted, everything grinds to a halt.
For a real-world example, right now I’m working on a Scala program that does all the logic in beautiful async, event-driven fashion, four threads serving thousands of requests at the same time – except I also need a couple of hundred threads to sit there blocked on database access, because JDBC is blocking and no-one bothers writing nonblocking database drivers for the JVM.
If you need a nonblocking library for X, you’ve got more chance of finding one in the node ecosystem than any other, sad to say.
No. 4 — October 31st, 2016 at 04:24
False: Twitter’s Finagle (Scala) has PostgRest and MySQL fully async jdbc alternatives.
No. 5 — June 6th, 2014 at 15:33
A. It’s funny you mention that a benchmark shows V8 to be 1x to 5x slower than Java. I’ve made a benchmark that shows Node.JS (and therefore V8) to be 1x to 5x FASTER than Java. Benchmarks can easily be skewed in whatever direction you want because some things are faster in some languages than other things in those same languages. There’s no “fair” comparison. You just have to compare real-world applications.
Just like you said in parenthesis, yes, I will point out that Node can take advantage of multiple CPU cores, however against your prediction, I will not naively say that there isn’t any thing else in the world that can take advantage of multiple cores. Using multiple cores isn’t anything new or specific to Node.
B. Q is super slow. Use bluebird instead. With bluebird, that problem you had with using callbacks as well as promises goes away because you can just use .then(bluebird.promisify(task2)())and if you’re like me and writing bluebird.promisify is just too long, you can say var p = bluebird.promisify. Then all you have to do is run .then(p(task2)()). Or, when you say var task2 = require(‘blah’) you could just use var task2 = p(require(‘blah’)), and that way you could treat task2 just like task1 and task3.
Bluebird also doesn’t require you to run .done() and as for error handling, you could just define a function to handle errors and then pass it in every time instead of making a new function every single time.
LinkedIn. Are you saying that they aren’t using a gigantic enterprise codebase anymore? IMO their node codebases do way too many things and can be pretty enterprisey (and that’s just their open source code; imagine how bad the code that they don’t make public is). Also, gigantic enterprisey codebases are just like lean codebases. They were all written from scratch. Unless by “written from scratch” you mean that they lack any external dependencies written by 3rd parties, in which case their Node codebases weren’t written from scratch.
Although you’re right about the comparison not being apples-to-apples (and Mongrel is a great example of that)
Existing JS: A. You’re right. Front-end devs still need to learn a bunch about Node to use it. Node is no different from others in this respect.
Existing JS: B. You can use traceur as a bandaid to completely fix this. Bandaid solutions aren’t elegant, but no language/paradaigm/whatever is without warts. Bandaid-style solutions let us cover them up, but they’re not just for Node.
You can divide your code up so that the reusable parts are reusable, but some parts won’t be. This is a good thing, because it encourages you to divide your code up, which is very important, and not at all specific to JS. Are you suggesting that having one huge monolithic “main” function is the way to go? Of course not! We split our code up, and some parts happen to be reusable, which is very nice (although I wouldn’t say it’s a “must-have feature”).
NPM: putting search results in order of popularity would be awesome, and it is a missing feature. I do agree that choosing the right module isn’t an ideal process with NPM, however it is a pretty good package manager when compared to others.
Fast! MVP! I hate those people and completely 100% agree with you on this point.
No. 6 — June 6th, 2014 at 15:42
I view node the way i view _why’s camping. Its a great framework for making a simple http glue layer. I have a toy project- a very simple game with a node json http backend. It has about 5 endpoints, and its fun to write. And i don’t mean ‘ok’ when i say ‘fun’- i actually mean fun. There are no models, and very little in the way of business rules. Node just fetches values from postgres and sends them back.
That said, i’ve tried and abandoned a vast number of styles, libraries, helper languages, parallelization strategies and even an entire architecture (tldr- don’t even look at socket.io, that shit just doesn’t work) to get to the small code base I enjoy working with now. Its a small project, so this has all been part of the fun. I’m sure it would be hell if the project grew much beyond its current scope.
God, I miss _why.
No. 7 — June 6th, 2014 at 15:55
I had a client who wanted a static website and insisted on using node.js when I strongly recommended using php. They did not listen. I did not do the project. They went ahead and got a developer who was ‘philosophically against php, javascript is future’.
I checked out their website after reading this article today and it loaded a lot slower than their original PHP website. It was also missing a ton of features. I can only imagine what happened, the same thing that happened at my old job using node.js: used the wrong tool for the job and ended up spending most of the budget fighting fires associated with the tool decision.
No. 8 — October 13th, 2016 at 19:52
The site loading slow would have more to do with not having a CDN setup rather than the backend language. Your not going to see performance issues until you’re handling a ton of traffic, and even then you have things like autoscaling on AWS which make the actual language a non-issue.
No. 9 — June 6th, 2014 at 16:25
Hey, I’ve been doing some development with Koa.js and Node 0.11+(generators FTW) and it has been a breeze to work with callback hell and exception catch.
No. 10 — June 6th, 2014 at 19:47
“Oh, just some unproductive ones like Java, Go, Erlang (HiPE), Clojure, C#, F#, Haskell (GHC), OCaml, Lisp (SBCL). Nothing that you could write a web server in.”
If you would bother to look at studies, these languages tend to be dramatically more productive than Javascript.
“Nothing that you could write a web server in.”
They all also have way, way more webservers than Javascript does. Those webservers are also mostly dramatically shorter, simpler, and faster than Node.
Please stop giving the community advice based on data unsupported opinion. Thanks. Node is nothing even similar to fast.
No. 11 — June 9th, 2014 at 12:59
Sorry, I should have instructed people to put on their “snark goggles” beforehand! You can obviously build a web server in nearly any language, and at one point I was particularly interested in the state of Haskell web frameworks / servers.
No. 12 — August 24th, 2016 at 15:02
I think you have fallen victim to Poe’s Law: https://en.wikipedia.org/wiki/Poe%27s_law
No. 13 — June 6th, 2014 at 19:55
yeah, you are mostly right. JS and Node can stink but the alternatives are full with stuff that are tempting programmers to create non-essential complexity. On the right projects, node is fine enough. I have my own sollutions to orchestrate node micro-services in such a way that complex stuff become doable with node without usual ugliness. Developers love node for some reasons and when you love you forget some non-essential issues…
No. 14 — June 6th, 2014 at 22:04
“The second are those who are so dependent on JavaScript that they need to use JS across their browser, server, database, and laundry machine.”
I think this is an important point. Of course some other server language may more efficient, fast, fun, hipster, easier, whatever, and waaay better than Node, but in the end most people pick a languages that they prefer or know, whether it’s a good fit or not. And apparently there are a lot of developers that were originally doing front-end that needed something to be done in the back-end.
No. 15 — June 7th, 2014 at 04:55
Great post. I’ve been waiting for someone to do this kind of write-up for a long time.
It’s funny, but it seems like most of the node.js programmers out there don’t really have a grasp of what their other options might be. About a month ago I met a node.js guy in a bar after some user group, and totally blew his mind with F#’s async workflows.
No. 16 — June 7th, 2014 at 06:39
Thou node is of course is a hype, i found myself writing simple servers on it quite often and with good results. My method of choice to get rid of callback hell is fibers (that are not mentioned in linked article) which make everything better for like 2% cost of function call.
No. 17 — June 7th, 2014 at 08:11
[…] The emperor’s new clothes were built with Node.js | Notes (beta) There are plenty of people lambasting Node.js (see the infamous “Node.js is cancer”) but proponents tend to misunderstand the message and come up with irrelevant counterpoints. It’s made worse because there are two very different classes of people that use Node.js. The first kind of people are … […]
No. 18 — June 7th, 2014 at 09:23
Wow, that was a very thorough analysis of the shortcomings of Node (and Javascript in general). But I think it somewhat misses the point.
I use node for fast prototyping because
i) the package ecosystem is great and
ii) exactly because I don’t want to care about multithreading issues.
I don’t find that hard to reason about callbacks and promises. After a while you become used to and you just don’t care. And if you really need to write lean ‘a-la-Go’ code as you have shown, you can just use ES6 generators.
Bonus: You also get meta-programming with sweetjs, if you want to.
No. 19 — June 8th, 2014 at 03:10
I more or less had this conversation last week, Node.js Vs erlang with some guy who could not understand that the problem with blocking was only that Unix Processes are too large, and if you use erlang blocking becomes a 100% non issue
No. 20 — June 9th, 2014 at 10:59
«what languages/implementations are typically faster than JavaScript/V8? Oh, just some unproductive ones like Java, Go, Erlang (HiPE), Clojure, C#, F#, Haskell (GHC), OCaml, Lisp (SBCL). Nothing that you could write a web server in»
^^^^
amazing bullshit
No. 21 — June 9th, 2014 at 13:03
nordicdyno
your sarcasm detector is broken…
No. 22 — June 9th, 2014 at 13:04
Eric, i’m afraid you’re doing it wrong. true, continuations do not have a very high-level support in JS. then again, they’re *not* threads, and that is very explicitly so: threads are a can of worms, since they are run preemptively and, thus, violate *lots* of assumptions about sane programming (leading many smart people, including Guido van Rossum, to refusing writing threaded code).
now if you’re with me and agree that having the VM decide when to do context switching is a bad idea, you’ll end up having it to do yourself. given that, callbacks are one of the clearest way to organize your code. the upcoming ` yield` keyword (available as of NodeJS 0.11.x) will make many use cases a lot simpler.
you’re discussing promises using Q and using async.js as an alternative. i agree promises are a bad idea; i used them intensively for some time and then abandoned that approach for all the boilerplate, all the function wrapping and all the added complexities promises bring to the table.
i’m using async.js these days when i have to e.g. execute a limited number of concurrent http requests and collect all the results. it’s great you can do that in NodeJS with little extras added—many languages (Python for one) would tend to make that task much more difficult!
one solution to handling concurrency that you do not discuss is very obvious for me, and that is creating a JS dialect that has advanced language constructs (think defer, await) which then get translated into plain JS before getting executed. true, that means the code you’re running is not identical to the code you’re writing, but done right, it’s a great solution, because you can stop writing boilerplate and start writing down the essential parts of your program.
i believe this way of ‘meta-coding’, if you will, is the right way, because we’ve essentially been doing this ever since programming in languages got invented (by Grace Hopper in the 1950s), and because there is no way a single language can be standardized in way that satisfies all users. and it doesn’t have to.
No. 23 — June 9th, 2014 at 13:06
Thanks for your comment. I briefly mentioned the possibility of compiling a modified or different language to JavaScript (others have also mentioned ES6->ES5 compilers). But the further you get from “regular JavaScript”, the more compelling it is to just use another language entirely.
No. 24 — June 9th, 2014 at 13:22
Yes, writing multithreaded code can be difficult, but there’s a middle ground between preemptively scheduled code and callback hell. Especially for web servers, it’s natural to have each request in a different thread—then there are fewer shared objects to reason about.
No. 25 — June 9th, 2014 at 13:04
Some of your points are perfectly valid while I find that some others are the dev/dev lead/architect’s faults.
Take promises: it is the task or the development lead to, at the beginning of the project, select and document whether promises will be used, which library will be used and how libraries that do not provide promises will be wrapped (or not wrapped at all), ensuring that all code is written consistently and according to clearly stated guidelines. There are also nice code analysis tools available for JavaScript code that will ensure that everyone is using .done() with their promises, just like we have static code analyzers for Java.
And same thing with the Android notification libraries. It’s not Node.js’ fault that people like to reinvent the wheel, and as developer you can’t just pick one and hope it works so hopefully devs are smart enough to do some due diligence (document the requirements that the library needs to address, write a small prototype, look at popularity/license/roadmap, etc) and select the one that is most suitable.
Abut NPM, it seems to me that you’re mixing repository handling with dependency management. Nom *is* great for dependency management but if you don’t have a private nom repository then it’s your fault, not NPM’s. There are quite a few solutions available out there to take care of that, and even these days Artifactory provides native support for Node.js artifacts. Again, do your due diligence, understand how it works and if being without the central NPM for a few hours/days is a major risk for you then build your way around it.
No. 26 — June 9th, 2014 at 13:21
Apparently, the subtleness of your sarcasm was lost on some. Nice write up.
No. 27 — June 9th, 2014 at 14:00
“I briefly mentioned the possibility of compiling a modified or different language to JavaScript (others have also mentioned ES6->ES5 compilers).”
oops yeah, my bad, you did mention it.
“But the further you get from “regular JavaScript”, the more compelling it is to just use another language entirely.”
i do not think so. JavaScript is a (great) language that runs in a (great) VM. these days you have a fairly wide choice (CoffeeScript, TypeScript, SweetJS, Gorilla, Python, …) in what lingo to express yourself and still get readable JS to run inside V8/NodeJS. to ditch V8 just because you dislike braces or don’t want callbacks/event handlers to handle asynchronous stuff is to throw out the VM with the bath water. i mean, Python, Perl, PHP, Java, all these are not only languages with syntax and semantics quite different from JavaScript, they are also VMs that are fundamentally different from NodeJS.
“Especially for web servers, it’s natural to have each request in a different thread—then there are fewer shared objects to reason about.”
i beg to differ. threading has always been the band-aid you deplore, it has always been—for *logical*, not for *technical* reasons—fundamentally wrong. if you think it’s natural for a web server to use threading, think again; a single example: some PHP modules may cause hard-to-find subtle errors in your Apache (http://www.zerigo.com/article/apache_multi-threaded_vs_multi-process_pre-forked). i mean, this must be the most classical web server setup evah, Apache and PHP being the veterans of web serving, and still they don’t get threading right. nobody ever will (http://c2.com/cgi/wiki?ThreadsConsideredHarmful).
No. 28 — June 13th, 2014 at 04:22
Why on earth would you point to PHP as an example??
No. 29 — June 9th, 2014 at 15:56
Instead of whining about callbacks and complex exception handling you should just use solutions like fibers or streamline.js.
Here is how I write your example (and how our team has been coding with node for more than 3 years):
function dostuff(_) {
var z = task3(task2(task1(_), _), _);
return z < 0 ? 0 : z;
}
BTW, exceptions *are* properly handled: good old try/catch/finally works as you would expect; you don't have to test error codes after every call like in Go!
So you are not doomed, you can use node.js and yet write "normal" code! Then you can enjoy the simplicity of having one language (and a fun one) on both client and server.
No. 30 — June 13th, 2014 at 04:15
You didn’t mention that streamline.js introduces a compilation step into your workflow. You’d think that all of the work put into compile-to-JS solutions out there, someone could have put the work into making node.js itself not require such workarounds. But yes, this may be the closest thing to a not-awful style of coding in node.
No. 31 — June 9th, 2014 at 16:11
[…] start with blog posts that give general commentary on the reactive world. Start with The emperor’s new clothes were built with Node.js, which aims to put some sense into the Node.js hype. There is also a very good discussion on […]
No. 32 — June 9th, 2014 at 16:25
Your “classes of people that use Node.js” introduction doesn’t cover my case which I think shouldn’t be neglected: Front-end developers that need server-side processing + database for one of their projects. Using Node in this scenario is convenient.
No. 33 — June 13th, 2014 at 04:10
Is it, though? Is node *easier* than picking up another language and framework? See the section about frontend devs working on the backend.
No. 34 — February 23rd, 2016 at 22:46
Whatever happened to the axiom, “Use the best tool for the job”? JavaScript on the server side is NEVER the best tool for the job. The only reason people cite for using JS is that it saves them the effort of learning another language. Wow, how lazy can you be?!
Node by itself is not a sufficiently good reason. People have been creating fast, powerful server solutions for decades in languages other than JS. There’s really no rational reason to choose JS.
No. 35 — June 9th, 2014 at 16:56
[…] A provocative post by Eric Jiang, entitles “The emperor’s new clothes were built with Node.js”, regarding the undeserved praise being heaped upon NodeJS. While I think he gets his analysis all right, he is still missing the forest for the trees. […]
No. 36 — June 9th, 2014 at 21:36
[…] theory suggests that synchronous or blocking model of I/O works something like […]
No. 37 — June 10th, 2014 at 07:03
This article could have done without the high-school grade shark. You’ve just taken a lot of out-of-context remarks and built a straw man argument around them.
V8 *is* fast – for a dynamically typed language.
NPM *is* good – specially compared to Go’s horrible package manager which can’t even handle dependency versioning decently. And yes, being able to share server and client code is quite a boon – even if you can’t fully use ES6, it saves you from writing redundant code and get redundant libraries on the client and server.
Ultimately, JS is just a scripting language with some juicy advantages over other scripting language. If you think you’re better off serving client-heavy web apps in Haskell and Lisp, more power to you.
No. 38 — June 10th, 2014 at 12:02
But Node.js is webscale!
No. 39 — June 10th, 2014 at 15:59
[…] months after a serious NodeJS consideration little nastities started showing up. No doubt that NodeJS really utilizes resources more for async but the fact you’re not […]
No. 40 — June 13th, 2014 at 04:30
[…] I read yet another blog post complaining about how concurrency is hard in Node.js. As is often the case, the examples […]
No. 41 — June 13th, 2014 at 16:20
Eric,
streamline.js does *not* introduce an explicit compilation step in the workflow.
Node.js has require hooks that let you transform files on the fly as they are required. This is used by most compile-to-js languages like CoffeeScript and streamline.js. Moreover the streamline.js hook caches the transformed files to speed up application startup. Our application has more than 100,000 lines of streamline.js code and it restarts in less than 1 second (vs. 10 seconds without the cache).
You can also pre-compile the files but that’s mostly used by library writers to package precompiled versions of their modules, it isn’t used in the normal dev process.
Regarding code sharing between browser and server, we do it but we actually have little code in common between the two. But it is not so much about how much code you share, it is more about building a common technical culture for the whole team and keeping things simple.
No. 42 — June 15th, 2014 at 21:12
This article is confusing. I think it is generally circular, and premised on anecdotes.
Proper analysis requires objective measurement. In addition, it must be contextually aware. A better article would have presented a strong argument for several objective measures (A language should perform X-type operations in Y-time; a language should be strongly typed, and so on). This wasn’t done. That would be fine if the title was “Some random thoughts about Node”.
Having established no comparative structure, the article can only assert unqualified comparisons.
There is also this strange misunderstanding about what the relationship between Node and Javascript is.
The key design strut of Node is that I/O is responsible for most “slowness”, so make I/O fast. Managing the thread pool that libuv uses to efficiently manage I/O is where the “fastness” of Node comes from — has to do with libuv (C, thread pool), not with V8.
Once you’ve built this hyperfast I/O engine, how do you abstract away the complexities of multithreading? IOW, how do you model concurrency? Dahl could have used any language, but given that JS had no opinion on anything resembling a local system (the network interfaces, the drivers, the filesystem) creating the Node stdlib was simple — just build what isn’t there, and extend what is.
Now you have Javascript’s concurrency model — single threaded, event-loop based. This is the same concurrency model that NGINX uses, in solving a problem in common with Node — the c10k problem. A single thread with events is a reasonable, perfectly valid, concurrency model — concurrency != parallelism.
Threads vs. events — this is an old compsci argument, that continues to this day. A simple search will deliver several papers for study (such as http://www.csd.uoc.gr/~hy527/papers/threads-ousterhout.pdf). The point is simple: it is plainly disingenuous to assert that a language that does not model concurrency using the idioms of threads (synchronization, locking, etc.) cannot be a serious systems language.
Modern software is distributed software. This means a lot of I/O. Node does I/O fast by using threads. Modern software is often developed by large, distributed teams. Simplifying the way they model I/O has very real benefits, and single-threaded event-loop concurrency is one of those models — a well studied, perfectly valid model. This composite creates an excellent development environment (not even addressing how open source, a consistent stdlib, nom, and more contribute to this excellence), both enterprise-ready and relatively easy to learn and implement.
Node is a technology that some people and companies use. It is not a person, and therefore is not evil, or misleading, or a liar. Some who use it have had great success at enormous scale (Walmart, for instance: http://www.youtube.com/watch?v=lvZeY-xua70). Some perhaps should not have used it. That has to do with the quality of your system architect, and his/her understanding of testing, metrics, and strategy. It has nothing to do with Node. Those who like Node haven’t been tricked — again, Node has no agency. They are satisfied with what it is doing for them, and to simply assert that their satisfaction is due to their lack of “real” understanding or inability to comprehend the world around them is too ridiculous for words.
No. 43 — June 18th, 2014 at 02:05
[…] ??????????I/O ?????????????? […]
No. 44 — June 23rd, 2014 at 11:47
[…] C’est chez Eric Jiang, et si c’est plein d’opinion, d’ironie et de caricature, c’est quand même vrai sur le fond. […]
No. 45 — June 24th, 2014 at 21:47
At least for our use case this post is not even wrong.
Many websites, like ours, are more than just a backend and a frontend. Our backend, fronted by the flickr API, is written in php. Our mobile clients talk directly to this API. Our new web frontend, which we call the web client, talks to the same API. This layer is written in node which is very well suited for I/O bound work like aggregating API calls. Then we take this data and give it to models and views that run on the server and the client. On the server we can render html pages. Once those pages are received by the client our app becomes a single page app, running the exact same routes models and views. We didn’t choose node for performance. We chose it because it did exactly what we needed: it ran javascript and had fast concurrent i/o.
I’m sure lots of people are using node when PHP would work just fine. My own site is static html on nginx because that’s the right tool. We could have written our middle tier in something else, but then we’d have to write all the logic twice, just because a different language is slightly faster.
For the backend I’d love to see Go replace php, but that’s a whole different story.
No. 46 — June 25th, 2014 at 10:32
Yet another article created for trolling. Twisting facts, partial information on some topics, etc. It is fun to read and it is useful to bring overexcited with node.js people to the ground to make them look around, not focusing entirely on node.js.
But discussing its veracity is pointless, I believe.
No. 47 — June 30th, 2014 at 22:00
[…] The emperor’s new clothes were built with Node.js – I know sadly little about Node.js but this goes against the hype and is thus interesting. So what does Node.js give us? Performance 1-5x slower than Java [like Clojure] according to the Benchmarks Game (contrary to other benchmarks with the opposite result as mentioned in the comments), use of a single CPU/core on our multi-cpu, multi-core machines, callback hell. At the same time, there are good non-blocking servers available in other languages (Clojure’s http-kit, Vert.x, etc.) (Update: From the comments it seems that f.ex. the “callback hell” situation is geting better with 0.11, fibers and other things I do not know anything about. Also Sandro has a nice anti-comment (No. 36).) The Node.js Is Bad Ass Rock Star Tech 5 min video is a nice companion 🙂 […]
No. 48 — July 4th, 2014 at 21:44
[…] wrote a lot of good comments on my last post about Node.js. (They also wrote some bad comments, but the worst have been modded […]
No. 49 — July 5th, 2014 at 22:39
It’s like you’re in my head hahaha, great post.
No. 50 — July 5th, 2014 at 23:29
Nice article, I love node but I wouldn’t use for everything as the same with another tech.
By the way, I’m interested in buying a JS laundry machine, do you where I can buy it? ;D
No. 51 — July 5th, 2014 at 23:38
As a response to lmm up there on the comment that says Scala doesn’t have async database drivers, sure it doesn’t:
https://www.google.com.br/search?q=postgresql+async+scala&oq=postgresql+async+scala&aqs=chrome..69i57j69i65j69i60l4.3865j0j7&sourceid=chrome&es_sm=119&ie=UTF-8
https://www.google.com.br/search?q=mysql+async+scala&oq=mysql+async+scala&aqs=chrome..69i57j69i60j69i61l2j69i59j69i61.2226j0j7&sourceid=chrome&es_sm=119&ie=UTF-8
And there’s also twitter’s MySQL finagle service that I don’t know if it works or not but the source code is available.
There are a lot of async libraries for a lot of stuff both in Java and Scala.
No. 52 — August 26th, 2014 at 17:02
[…] hay que olvidar leer algunos artículos que lo critican con argumentos como La nueva ropa del emperador está escrita en Node.js y algunos comentarios al respecto publicados en […]
No. 53 — October 15th, 2014 at 20:02
I just stumbled across this writeup, very well written! It was clear and serves as a great resource to those evaluating Node.js.
No. 54 — October 27th, 2014 at 14:38
It seems that https://github.com/xicilion/fibjs solves the manual thread management problem you mentioned.
No. 55 — January 20th, 2015 at 17:32
Curious to see that most of the comments defending Node seem to follow the same pattern — along the lines of: “But if you use the little-known BeardedHipster.js, or perhaps JoesAsynchLib.js, or, if you’re really in the know, IHave100DownloadsAsynchLib.js, then you no longer have to use .done to avoid eating exceptions. On the other hand be sure not to mix any of these with MarysAsyncLib.js because that depends on the soon-to-be available yield keyword.”
Precisely the sort of duct tape and spit nonsense that gives Node a bad reputation in the first place, and what the author is rightly lambasting.
No. 56 — March 9th, 2015 at 21:11
Great article.
I like Node JS because I like JavaScript as a language.
Plenty of developers do, it’s the reason why JSON is such a common format for serialization. It’s flexible, precise and very easy to read. As is JavaScript itself.
Callbacks are undoubtedly an unusual construct to grasp, but every language has it’s quirks. Java, for example, enforces OOP practice, but when you really give it a bit of thought, one could see that as bad language design decision.
If you doubt that, just look at the type class and property names you can find in any non trivial Java project, and then compare them to the property names you’ll find in any non trivial project in almost any other language…
That’s why GWT died out a long time before JQuery, even though both projects started out at around the same time…
No. 57 — April 26th, 2015 at 03:14
See async fail:
https://gist.github.com/mschwartz/7761357
No. 58 — June 8th, 2015 at 19:08
I really like node and it suits a particular niche for me extremely well. On the other hand I also like this article. As someone who programs a moderate amount in node.js and in several other languages I can confirm that most of your points are valid (and the rest I have not looked at).
Node is extremely good for what I need in certain cases (I have used several languages for making a certain type of application and nothing has been more well suited than node.js) but it can be a lot better. Not all of it is on node, JS has a lot of its own issues as well. Despite being a bit proponent of node.js, I’ve found it very hard to raise legitimate criticisms among other node.js users.
I could list several other criticisms of node.js and Javascript but that one has to be my biggest one. The attitude of some of the community can be very trying at times and such an attitude is not going to help make node.js a better platform.
No. 59 — June 21st, 2015 at 23:14
Of all the comments I read in the article,
John Haugeland’s is priceless! You reading this John? Oh dear God, you don’t actually think that’s a compliment do you? ROFL!!
No. 60 — July 26th, 2015 at 18:38
[…] store important data in your application database, and I hope you like to implement your apps in a code mess that doesn’t perform or scales on anything bigger than a hello world app. I’d rather leave these things to the […]
No. 61 — August 19th, 2015 at 06:49
[…] The Emperor’s New Clothes Were Built with Node.js […]
No. 62 — November 6th, 2015 at 18:40
Great write up! It’s like you wrote my thoughts in such an elegant and entertaining way. Like your sarcasm, but seems to be lost on most of the commenters.
I’ve been following go a bit and it seems to be a nice alternative to node. I’m predicting a big switch from node to go in 2016 will be significant.
No. 63 — February 17th, 2016 at 19:08
I perfectly agree. There are 1*10’^6 languages out there: wasn’t it possible to develop nodejs over a REAL language? JS and nodejs are the worst things I had to work with in my life in computer engineering.
No. 64 — March 3rd, 2016 at 21:12
I find it interesting that everyone continues to argue about the low-level technical aspects of NodeJS, which are valid I might add. However for me the biggest issue is the lack of strong typing. This is a huge problem for large enterprise systems and well… anything beyond “todo list” application. As soon as you think about the logistical issues of refactoring large javascript applications _reliably_ all other arguments pale into insignificance.
There seems to be a drive as well to have everyone programmer in the same language and they miss the point that languages are really domain specific. As I tutor up and coming programmers I remind them that they are becoming _programmers_…. the language is irrelevant and the skills are completely transferable.
No. 65 — March 8th, 2016 at 20:36
I définitly hatte Nodejs.
I did benchmark between python asyncio and nodejs and the winner is asyncio.
Nodejs npm are a big JOKE
No. 66 — May 3rd, 2017 at 17:44
This is a really great post. Excellent writing.. Things have really changed from back in the day. Server side javascript, lol