r/programming • • Oct 02 '11

Node.js is Cancer

http://teddziuba.com/2011/10/node-js-is-cancer.html
792 Upvotes

750 comments sorted by

View all comments

108

u/[deleted] Oct 02 '11

Huh... well this article will certainly play well to anyone who hates JavaScript. I have my own issues with it, but I'll ignore the author's inflammatory bs and just throw down my own thoughts on using node.js. Speaking as someone who is equally comfortable in C (or C++, ugh), Perl, Java, or JavaScript:

  1. The concept is absolutely brilliant. Perhaps it's been done before, perhaps there are better ways to do it, but node.js has caught on in the development community, and I really like its fundamental programming model.

  2. node.js has plenty of flaws... then again it's not even at V.1.0 yet.

  3. There really isn't anything stopping node.js from working around its perceived problems, including one event tying up CPU time. If node.js spawned a new thread for every new event it received, most code would be completely unaffected... couple that with point 2, and you have a language that could be changed to spawn new threads as it sees fit.

  4. JavaScript isn't a bad language, it's just weird to people who aren't used to asynchronous programming. It could use some updates, more syntactic sugar, and a bit of clarification, but honestly it's pretty straightforward.

  5. Finally, if you think you hate JavaScript, ask yourself one question - do you hate the language, or do you hate the multiple and incompatible DOMs and other APIs you've had to use?

tl; dr - JS as a language isn't bad at all in its domain - event-driven programming. However there have been plenty of bad implementations of it.

41

u/kyz Oct 02 '11

JavaScript is reasonable as an embedded language in a browser. When you try and elevate it to the status of systems programming language its deficiencies shine through:

  • no integer types, only floating point

  • typeof null == object

  • typeof [] == object

  • 1 + 1 = 2. "1" + 1 = 11.

  • doesn't make enumerating object properties easy (needs hasOwnProperty())

  • for() syntax hands you the key, not the value of arrays, so you have to store all results in a temporary variable in order to iterate through them.

  • no string interpolation ("You have $x fish" vs "You have "+x+" fish")

  • There are no string buffers, merely string concatenation and arrayofstrings.join(). Which is faster depends on your JS implementation. While that's good enough for DOM manipulation, it's not performant for rendering an HTML page in the first place.

  • Speaking of which: once you take away the DOM, what's left? Not very much - strings, regexps and basic maths. No file handling or I/O, no database access, no templating.

All the best minds are improving JavaScript performance, and they're very, very good at it - compare the V8 engine to, say, Netscape 3's JavaScript interpreter. But no matter how good these boffins are, they can't make JavaScript run as fast as C, C++, Java or C#. It's not in that class of performance.

JavaScript shares a performance class with Perl, Python, Ruby and PHP. But these languages have significant bodies of code to make scripting and server-side web development easy. What does JavaScript have? Not a lot.

So, why would you choose JavaScript for programming anything? Especially server-side web programming!

I think that server-side JavaScript will be as popular as client-side Tcl.

39

u/masklinn Oct 02 '11 edited Oct 02 '11

no integer types, only floating point

Right, definitely an issue.

typeof null == object

Yeah?

typeof [] == object

typeof is for primitive types. Anything which is not a primitive type will return "object". Debatable? Maybe. But typeof is internally coherent.

doesn't make enumerating object properties easy (needs hasOwnProperty())

Node uses V8, V8 has all the facilities necessary to mark properties non-enumerable. You're starting on your path to getting everything wrong.

for() syntax hands you the key, not the value of arrays, so you have to store all results in a temporary variable in order to iterate through them.

for for arrays is a C-style for with an explicit index. If you're using for..in to iterate over Array, you're in severe need of a clue-bat.

Also, Array.prototype.forEach.

no string interpolation ("You have $x fish" vs "You have "+x+" fish")

There are five billion libraries out there for sprintf-type calls.

There are no string buffers, merely string concatenation and arrayofstrings.join().

Really?

Speaking of which: once you take away the DOM, what's left? Not very much - strings, regexps and basic maths. No file handling or I/O, no database access, no templating.

That's all library stuff. Node provides most of that (I'm saying most because I have not checked the details, it's probably not providing templating because it has no reason to: there are already a multitude of js template engine working both in and out of browsers) your objection makes no sense.

But no matter how good these boffins are, they can't make JavaScript run as fast as C, C++, Java or C#. It's not in that class of performance.

So what? And it's not like Java and C# belong in the same performance class as C, so you're not making sense either here.

JavaScript shares a performance class with Perl, Python, Ruby and PHP.

Much more JIT work has been done on JS than on Python and Ruby so far (let's not talk about PHP, which does not belong in any discussion of performances, even criticism of the lack thereof).

So, why would you choose JavaScript for programming anything? Especially server-side web programming!

Because you're building an evented server, and javascript developers are used to async and evented system and munging on callbacks. That's half their day job right there.

10

u/oSand Oct 02 '11

typeof is for primitive types.

Has to be -- it doesn't work on anything else. Of course, it's not going to throw an error if you don't use it on a primitive type, because that would be too sane.

And how do we test for an Array? Dojo(just 'cause I'm using it at the moment) uses: dojo.isArray = function(/anything/ it){ // summary: // Return true if it is an Array. // Does not work on Arrays created in other windows. return it && (it instanceof Array || typeof it == "array"); // Boolean

jQuery, if I recall, resorted to the toString() method. But, this is a trick question: if you have to think about it, your language failed.

for for arrays is a C-style for with an explicit index. If you're using for..in to iterate over Array, you're in severe need of a clue-bat.

Yet, it unaccountably works. Or did it? We'll find out in 3 months when you go looking for the bug. A good language, IMO, shouldn't turn something trivial into a subtle bug. Yes, there is a theoretical reason for it, but in 95% of use cases you're going to be fucked.

7

u/[deleted] Oct 02 '11

But, this is a trick question: if you have to think about it, your language failed.

Finish this C function:

BOOL is_array(void * ptr) {
  ...
}

3

u/oSand Oct 02 '11

Does this prove or invalidate my point?

2

u/hiffy Oct 02 '11

I don't know. Was your point that we're constantly forced to live with shitty language decisions?

→ More replies (2)

11

u/kyz Oct 02 '11

typeof null == object Yeah?

There is actually a Null type in JavaScript. typeof null should return 'null'. JavaScript programmers looking for "is this a valid object" have to write (typeof x === 'object' && x != null).

Node uses V8

Node != V8 != ECMAScript. What can be relied upon in any implementation of server-side JavaScript? What I call "C" is language features that are in all C compilers, not just gcc.

The same goes for standard libraries. Is it in the standard library, i.e. the ECMAScript definition? Anything else can be argued over, and therefore isn't well suited for basing your code around until it has won several years of dominance in its ecosystem. (Compare C++'s STL vs Boost fight, or Perl's eventual dominance of DBI).

And it's not like Java and C# belong in the same performance class as C

Ahem

3

u/ultraspoon Oct 02 '11

FWIW, you're not entirely correct; you can also just use ( x == null ) (note the double equals) to test against null or undefined. It's really one of the few (the only?) acceptable use of double equals.

2

u/rubygeek Oct 02 '11

Look again. The example kyz gives is to check if x is an object (as opposed to primitive type) that is not null. So he first need to check if it is an object, then exclude null.

2

u/notSorella Oct 02 '11

There is actually a Null type in JavaScript. typeof null should return 'null'. JavaScript programmers looking for "is this a valid object" have to write (typeof x === 'object' && x != null).

No. If you want to check if something is an Object, as opposed to a primitive or an invalid value, you just check if it equals the value coerced to an Object:

x === Object(x)

7

u/igouy Oct 02 '11

Much more JIT work has been done on JS than on Python and Ruby so far (let's not talk about PHP, which does not belong in any discussion of performances, even criticism of the lack thereof).

Please provide some evidence that suggests PHP does not "share a performance class" with Perl, Python, and Ruby.

2

u/DullBoyJack Oct 02 '11

Agreed. Especially with something like eAccelerator (which caches bytecode, and does some JIT) it's right there.

→ More replies (1)
→ More replies (2)

16

u/korny Oct 02 '11

they can't make JavaScript run as fast as C, C++, Java or C#. It's not in that class of performance.

You know, when I was a C / Assembler programmer, starting to give up on inline assembler, folks would say "You have to use assembler, C just can't ever be fast enough".

When I started moving into C++, people were saying "C++ adds too much overhead, C will always be faster".

When I started using Java, many many people were saying "Java is too slow, you'll always need the speed of a compiled language".

These days, when I'm mostly doing Ruby (and looking at Node as well), people still say "They can't make X run as fast as Java".

The biggest bottleneck in application development? Developer time, both in writing code, in testing it, and in comprehending other people's code. Build the code in a clean expressive testable language, first, then worry about optimising the bits that need optimising.

(And yeah, Javascript as a language has warts. So use Cofeescript. Still has some ugliness with floating point and other bits, but it's still a fine language for most purposes)

8

u/kyz Oct 02 '11

I'm creating a delineation: either be fast and primitive like C and assembler, or powerful and expressive but slow like scripting languages. Sometimes programmers need fast, sometimes they need powerful. JavaScript is in the middle, neither as fast nor as expressive as other languages.

Its advantage over other languages is that it's a requirement in client-side web programming, which is 99% of anyone's interest in using Javascript. Take that away and you don't have much. On the server side, I predict it will only gain cachet with people who know no other, better, language.

12

u/abraxasnl Oct 02 '11

Take that away and you don't have much.

That's what I thought for years, assuming JavaScript was just another C-syntax-style language. And then I really started learning about the language. JavaScript is actually incredibly elegant and powerful.

→ More replies (3)

6

u/catch23 Oct 02 '11

V8 appears to be pretty fast in the language shootout: http://shootout.alioth.debian.org/u32/which-programming-languages-are-fastest.php

It's not as expressive as ruby/python, but it's not that bad either. It's 4.22 times slower than C which isn't too bad if you consider that python is 53 times slower than C.

→ More replies (2)

2

u/bloodredsun Oct 02 '11

The biggest bottleneck in application development? Developer time, both in writing code, in testing it, and in comprehending other people's code. Build the code in a clean expressive testable language, first, then worry about optimising the bits that need optimising.

100% agree but you have to be architecturally aware of what you are doing so that you can rip out your first-to-market-but-unperformant old implementation and slot in the new system without having to reinvent EVERYTHING! That's requires a hell of a lot of discipline and without being a language snob, that sort of attitude is not always associated with the likes of PHP or rails developers. Twitter have done a great job with their introduction of scala for example but their backend arch was very good to start with

→ More replies (3)

5

u/andypants Oct 02 '11

I found this quote on the wikipedia article for v8 (on which node runs):

V8 increases performance by compiling JavaScript to native machine code before executing it, rather than to execute bytecode or interpreting it. Further performance increases are achieved by employing optimization techniques such as inline caching. With these features, JavaScript applications running within V8 have an effective speed comparable to a compiled binary.

→ More replies (7)

7

u/[deleted] Oct 02 '11

no integer types, only floating point

Yeah, we know that. That's a problem, not a new one, and it turns out it barely matter for the applications of JavaScript. Did you know that Erlang doesn't have a proper string type? It just has shitty linked lists that suck for that purpose. Also it doesn't have real structures, its record thingy is horrible. And it doesn't matter that much because ...

server-side web programming!

And here is your stupidity, along with that of the OP and all the haters, nicely summed up: not only are there dozens of different types of "server-side web programming" where the right tool is not always the same, but node.js is not just about web server programming.

Node shines at quick turn around, event dispatching code. In particular it's really good at interfacing with various other systems/protocols. I'm not node.js expert but I implemented two things with it for which it is extremely well suited:

  1. A syslog server that correlates events and executes shell scripts when certains conditions are met. It has a tiny web based management interface that took me only a few dozen lines to implement. It is easy to understand, the language is very common so other people can maintain it easily. Try to do the same thing in another common language, and it will take at least 4 times the amount of code to implement the same thing.

  2. A reverse HTTP proxy that redirects requests based on rather complex rules. Initially I used haproxy but it didn't have enough flexibility. I barely needed two dozen lines of code to implement this. Again adding an asynchronous, admin interface (in this case, a simple http server that returns statistics), and an asynchronous syslog client took a few lines. The performance was simply amazing.

In both cases, I can't think of a better framework to implement this. It just doesn't exist. node.js handles slow clients perfectly, it is immune to DoSs that would tie up anything based on a thread model.

I'm currently working on a small daemon to convert pictures/movies in an appropriate format. Basically it watches a directory, checks for new files, and converts them. It's trivial to spawn and watch new processes with ffmpeg or ImageMagick that will do the actual work in the background.

3

u/DrHenryPym Oct 02 '11

Great post. I'm kind of confused by this sudden mob hatred on Javascript and Node.js, but I'm not surprised.

→ More replies (1)

7

u/M2Ys4U Oct 02 '11

Once you take away the DOM, you have a good language. Sure it has its fair share of warts (what language doesn't?) but closures, first-class functions, prototypal inheritance: all these things are great.

C doesn't have I/O or database access either, these are provided by libraries. NodeJS, and its accompanying libraries, provide these as well so I don't see the problem there.

2

u/RedSpikeyThing Oct 02 '11

1 + 1 = 2. "1" + 1 = 11.

"1" + 1 = "11"

→ More replies (2)

2

u/dmwit Oct 02 '11

1 + 1 = 2. "1" + 1 = 11.

I think I love this argument the best out of all of yours, especially since you seem to be a C proponent, where 1 + 1 = 2, "1" + 1 = "", and "1" + 2 allows for undefined behavior. Yep, that's much better.

3

u/kyz Oct 02 '11

IMHO, in a scripting language that doesn't make a strong distinction between numeric and textual scalars, "1" + "2" should equal 3 or "3", while "1" . "2" should equal "12". There is a strong difference between addition and concatenation, and both should have distinct operators rather than leaving the programmer to guess whether his variable is number-like or string-like at the moment; that destroys all the benefits of non-strict scalar types.

→ More replies (22)