Hacker News new | ask | show | jobs
by SomeCallMeTim 3481 days ago
It's also a rather convoluted set of examples.

If you're doing something in Node that takes nontrivial processing time (that doesn't just involve waiting for I/O), you're Doing It Wrong (tm).

Since the premise of "callback hell" is outdated, the only remaining point is that if you perform complex/time consuming calculations in NodeJS, it slows down.

If you want the most speed, or if you're going to be doing something like a Fibonacci calculation, you should write that (microservice) in Go instead. It's faster from the start (by 2x at least, probably a lot more if you're CPU bound), and GoRoutines can be spread across multiple threads, so a multi-CPU host can take advantage of all of its CPUs.

Oh, and the per-GoRoutine overhead is only about 4K on a Linux host, last I checked. True that Haskell has a smaller overhead per thread, but considering the speed advantage, I think the Go server would still win big on latency for the number of threads that did actually fit in memory.

1 comments

But if you're going to run to Go, Haskell, or something else to write micro-services to handle everything that Node doesn't do well, why not just ditch Node and write everything in that other language, since languages like Go, Haskell, Elixir, and Erlang are better and faster than Node at the things Node is good at as well?
But they aren't always. Go might, but I'd be less sure about Haskell in a fair test and Elixir/Erlang (as much as I love them and prefer them to everything else) are languages with strong benefits and strong drawbacks. Node actually does have some advantages.
Would you mind sharing some of those advantages of Node, and disadvantages of Elixir/Erlang? It's hard to have a meaningful discussion around vague assertions.
A key advantage that Node has? NPM with 350,000 packages.

Granted they aren't all top quality packages, but thousands are.

I was working on one project that used ZeroMQ, as a random example. There are excellent packages for Node, including a well maintained version for the newest 4.0 branch.

For Elixir, when a team wanted to interface using ZeroMQ, the best they could find was a "work in progress, not ready for production use" build that was a partial re-implementation of ZeroMQ 3.1, and that specifically lacked the elliptic encryption feature that we were using. The more mature ports to Erlang similarly doesn't support the encryption we were using. [1] There's one native binding that seems to only support 3.1 (at most) as well [2], but it's something you need to build and configure, as opposed to "npm install zeromq --save", or better yet, "yarn add zeromq", and then your project will work on any system without any complex build rules to get it working.

That's just one package that I tried to use, and it's a popular network message queue package (two full ports to native Erlang!). If I had tried to do something more obscure I'm sure I would have had even more problems.

Another key advantage is that there are probably 10x the number of developers ready to hit the ground running on a Node project than there are Go developers, or 50x as many as Elixir or Erlang developers. I don't know if you've tried to do much hiring, but it's hard enough finding developers for a language that's popular. (And no, I'm not counting "front end" JavaScript developers; if I were, I would have said 100x or more.) If you're hiring in an area that isn't highly tech focused, you might not be able to hire a single developer with experience.

[1] https://github.com/zeromq/ezmq/issues/31 and https://github.com/chovencorp/chumak (supports only the "NULL" security framework -- there's a note lower down on the page that Curve isn't supported)

[2] https://github.com/zeromq/erlzmq2

Node.js's NPM packages are notoriously dumb. How many of them are one-liners that only exist to compensate for Javascript's lacking standard library? How many of them are complete rewrites of other Node.js packages that do exactly the same thing?

Why would an Elixir programmer want to interface with ZeroMQ, when there are far better options for such communications built into the language itself? Node HAS to use ZeroMQ because it lacks the intrinsic ability to handle many problem spaces. Elixir and Erlang don't suffer from those shortcomings. In fact, they were designed to solve those types of problems. I've replaced ZeroMQ countless times when replacing Node code with Elixir code, and the end result has always been an amazing improvement in speed, stability, and scalability; not to mention code maintainability.

A lot of Node programmers tout npm as a great package manager, but how is it any better than gem, pip, and all the other package managers that it took its cues from? How is typing "npm install zeromq --save" any better or easier than typing "mix deps.get," "gem install zeromq," or "pip install zeromq?" Could it be that Node programmers are simply unaware than tools like npm have existed in other languages for years?

Finally, I'm sure there are 100X the number of Node programmers out there for every Erlang or Elixir programmer, but, when you need speed, stability, and scalability over trendiness, you really only need to have one.

Though, to be honest, most Erlang/Elixir devs would never think of using something like ZeroMQ as Erlang has more powerful and built in alternatives, or something like the Elixir Phoenix web framework that has built in much more powerful functionality. That seems to be an aspect of knowing the tools, easy to miss if you are new to the Erlang ecosystem. :-)
I beg to differ. ZeroMQ is fast and has bindings for most major languages [0]. So if you want to make native apps that speak over a very reliable channel, ZeroMQ is a great tool for interop. And its elliptic curve auth/encryption are super trivial to set up as well as being very fast, as opposed to getting https certificates pinned correctly on both the server and client.

Only if you only plan to ever speak to other Erlang/Elixir hosts would it make sense to use an Erlang/Elixir-only solution. And I will not even consider the option that writing a game (which is what I'm doing) in Erlang or Elixir is reasonable. Yes, it's possible, in a "Turing Machine" kind of way. But no, it's a terrible idea. Complex games don't break down into isolated functional chunks without actually making them much harder to design, maintain, and extend. I use plenty of functional concepts when I write games, where appropriate, but using a functional language would be a nightmare.

Phoenix is a web framework. "More powerful" functionality that I can't use for a particular project is a pretty profound waste.

Since I did actually abandon ZeroMQ for my game (when I decided that I needed to do most of the game as a web client anyway, and so I should just make the host app be built on TypeScript as well), I'm now using Socket.io, which surprise has an outdated port to Erlang [3] that doesn't support 1.0, and there's no native Elixir port. See a pattern emerging?

And since I mentioned speed was important: Kami, a Go-based web framework, benchmarks up to 4x faster than Phoenix. [1] Raw Go speed for the kind of thing I'd actually be doing is closer to 5x-10x that of Phoenix. [2]

By the way, it turns out there's an actively maintained Socket.io port on Go. And being able to spin up 1/8 the number of servers could realistically take my project from break-even to profitable.

[0] http://zeromq.org/bindings:_start

[1] https://www.techempower.com/benchmarks/#section=data-r13&hw=...

[2] Look at the fasthttp Go results on https://www.techempower.com/benchmarks/#section=data-r13&hw=... and https://www.techempower.com/benchmarks/#section=data-r13&hw=... -- my usage pattern would be somewhere between raw text and "single db" access, since my DB is Redis on localhost, so it's more like a cache than a Postgres/MYSQL lookup.

[3] https://github.com/yrashk/socket.io-erlang