Terminology is part of the problem here. Comparing "threaded" vs. "evented" may have made sense in, say, Windows in 2003 or some context where we are clearly talking "select loop" vs. "pthreads", but there are a lot of things that could be called "threading" models now. Well, sort of a lot of things, because they're all converging now on the same core primitive, leaving us with two basic cases here: 1. Old, synchronous code and 2. code running on the local select-like primitive that freely composes with other such code.
Node.js clearly wins to the extent that it is code of type 2 replacing code of type 1. But when you compare Node.js against other technologies of type 2, I find it hard to conclude that it really stands out on any front except hype. All the type 2 technologies tend to converge on equal performance on single processors, driven by the performance of the underlying select-like primitive, so what's left is two things: comparing the coding experience, where "evented" really loses out to thread-LIKE coding that actually under-the-hood is transparently transformed into select-like-primitive-based code, but is not actually based on threads, and two, dispatching the tasks to multiple processors, where Node.js doesn't even play.
A great deal, if not nearly all, pro-Node.js arguments persistently argue against systems of type 1... but they don't get that that's not actually the competition. It's the other type 2 systems that they are really facing, and Javascript isn't really helpful there. Events are a hack around the fact that Javascript's heritage is pure type 1, not a glorious feature, and I think you really ought to stick with the languages that are natively type 2, or functional enough that they made a smooth transition. Node.js is forever going to be a platform that spent a lot of its engineering budget just getting Javascript to straddle the divide from 1 to 2 with some degree of success, and that's going to be engineering budget you can't spend on your project.
I am not a specialist on this area. But please mention some interesting competitors to Node.js for your type 2?
Personally I also like the fact that Node is Javascript. I have looked at Scala several times and superficially, it looks extremely ugly. Clojure and Haskell might be interesting, but I worry that the non-modifiable memory could bite me in the end (plus, Clojure might force me to do too much dreaded Java stuff in the end). Erlang is fun because it is so freaky and different, but I am not sure how efficient it would be for writing huge amounts of code. It is also not written for performance, but for stability (according to it's inventor).
Which leaves what great alternatives? I have to admit, no other popular environments come to my mind. Arc, maybe?
You mentioned most of the ones I consider the real winners. Go is another possibility, though I'm not sure it fits in here; I don't know what sits at the core of the goroutines scheduler, but if it isn't select-like it probably easily could be. There are also a metric shitload of other event-based frameworks like Node.js, only for other languages, at varying levels of maturity and cruftiness.
(Though part of the reason something like Twisted is crufty is that the design forces in the domain push you in that direction. Twisted is crufty, yes, but it's crufty for reasons that apply to Node.js and Node.js will naturally either have to gravitate in the same direction or hit the same program-size-scaling-walls that drove Twisted in that direction in the first place.)
None of the environments are "popular" by any reasonable meaning of the term. Don't let the hype fool you, neither is Node.js.
If you like Javascript, use it, but like I said, be aware that you are paying a big price for jamming a type 1 language into a type 2 situation. (Same goes for all of the aforementioned event-based frameworks; I am not especially down on Node.js, I'm down on the entire idea.) I am reminded of those who insisted on using Visual Basic to do their object orientated programming in. Yes. It works. But you pay. You pay in a long series of little compromises that are easy to wave off individually but add up to major ongoing friction. In the medium and long term you are better off learning something designed for that niche, not jammed into it.
(And while the original article mentions it only in passing, that spaghetti code scaling wall for this sort of code is very real. I'd liken it to something O(n^1.3) as the code size grows; sure, it doesn't seem to bite at first and may even seem to win out over O(n log n) options like Erlang at first, but unfortunately you don't hit the crossover point until you're very invested in the eventing system, at which point you're really stuck.)
(Incidentally, why am I down on the whole idea of eventing? Because twice in my experience I have started on one of these bases and managed to blow out their complexity budget as a single programmer working on a project for less than a year. And while you'll just have to take the rest of this sentence on faith, I actually use good programming practices, have above-average refactoring and DRY skills, and use unit testing fairly deeply. And I still ended up with code that was completely unmanageable. Nontrivial problems become twice as nontrivial when you try to solve them with these callback systems; this is not the sign of scalable design practices. On the other hand, I've built Erlang systems and added to Erlang systems on the same time frame and the Erlang systems simply take it in stride, it hardly costs any complexity budget at all. And Erlang's actually sort of lacking on the code abstraction front, if you ask me, it's an inferior language but the foundational primitives hold up to complexity much better.
In fact, I'm taking time out from my task right now of writing a thing in Perl in POE, a Perl event-based framework, in which I have to cut the simple task of opening a socket, sending a plaintext "hello", waiting for a reply, upgrading to SSL, and sending "hello"s within the SSL-session to various subcomponents into six or seven-ish sliced up functions with terrifically distributed error handling, and even this simple bit of code has been giving me hassles. This would be way easier in Erlang. Thank goodness the other end is in fact Erlang, where the server side of that is organized into a series of functions that are organized according to my needs, instead of my framework's needs. The Erlang side I damn near wrote correctly the first time and I've just sort of fiddled with the code organization a bit to make it flow better in the source, this is my third complete rewrite of the Perl side. And I've got at least a 5:1 experience advantage on the Perl side! The Perl side requires a bit more logic, but the difficulty of getting it right has been disproportionate to the difference in difficulty.)
> Because twice in my experience I have started on one of these bases and managed to blow out their complexity budget as a single programmer working on a project for less than a year.
Could you please share a little more about this? I'm interested to know what it is you were building solo and the tools you were using, and what made it so difficult to maintain.
Not tried POE myself but it does seem to produce a wide love/hate divide among its users. AnyEvent (http://search.cpan.org/dist/AnyEvent/) seems to be the more pragmatic choice.
Thanks for the info. I don't have the experience yet, so I can't comment. Erlang definitely sounds good, too. My impression was that the hype had subsided recently, but maybe it is still going strong.
> Clojure and Haskell might be interesting, but I worry that the non-modifiable memory could bite me in the end
For the record, this is absolutely no problem given the generational GC in the Hotspot JVM; the structural sharing in Clojure's persistent data structures generate a little extra garbage, but it's barely a blip on the radar. Laziness can have more of an impact on memory usage, but it's usually really easy to spot.
Node.js clearly wins to the extent that it is code of type 2 replacing code of type 1. But when you compare Node.js against other technologies of type 2, I find it hard to conclude that it really stands out on any front except hype. All the type 2 technologies tend to converge on equal performance on single processors, driven by the performance of the underlying select-like primitive, so what's left is two things: comparing the coding experience, where "evented" really loses out to thread-LIKE coding that actually under-the-hood is transparently transformed into select-like-primitive-based code, but is not actually based on threads, and two, dispatching the tasks to multiple processors, where Node.js doesn't even play.
A great deal, if not nearly all, pro-Node.js arguments persistently argue against systems of type 1... but they don't get that that's not actually the competition. It's the other type 2 systems that they are really facing, and Javascript isn't really helpful there. Events are a hack around the fact that Javascript's heritage is pure type 1, not a glorious feature, and I think you really ought to stick with the languages that are natively type 2, or functional enough that they made a smooth transition. Node.js is forever going to be a platform that spent a lot of its engineering budget just getting Javascript to straddle the divide from 1 to 2 with some degree of success, and that's going to be engineering budget you can't spend on your project.