News for hackers. Stuff that matters.
Re:Hard-won lessons: Five years with Node.js by jimmywanger on Thursday April 20, 2017 @02:12AM (#14154347)
I replied in a sister thread, but here are some new points that are specific to your questions.

Node was decided upon before I joined the team, because some of the senior developers on the team were big members of the node team, and they also wanted to crank out something new in this greenfield project. In retrospect, and in my reading of the history, Node was sufficiently different and new enough that it was "ooh, shiny new toy".

JS/Node might be nice for scripting up a new demo that doesn't need to be maintained. I'd use Python/Django or Ruby/Rails myself, but whatever. Small projects that don't need to be supported to me seem pretty language agnostic. Do it in whatever tools you're most familiar with, and don't worry too much about fit.

For large production systems that need to be supported and maintained, it's awful. First, javascript is changing incredibly rapidly. It seems like every couple of months, you're updating your libraries and there's a new "best practice". You're faced with updating all your already written code to use the new canonical way of doing things, or you're stuck with a mishmash of ways to do things all in production, and new engineers have to constantly ask what the new hotness is.

Stack traces are useless. Yes, this function got called with invalid argument values from the event loop. What function called it, and what arguments did it have?

Javascript itself basically has objects that are just JSON objects. When you're passing them back and forth, you get the irresistible urge to add "optional" fields just to pass one extra parameter for a use case. You generally end up with a big ball of wax parameter object being passed around with fields with unclear purposes.

Libraries are often half-baked. They work most of the time, and try to do the right thing, but sometimes just behave unexpectedly. I'm not quite sure whether to blame the people who wrote the libraries, or if it's the language itself that tends to encourage things like that. I'm guessing it's six of one, half a dozen of another.

I can't stand NPM. A lot of times, two libraries that you want to include will depend on incompatible versions of another, shared library, and you can download a NPM dependency tree for each library to overcome that. Everything hangs together, sort of.

It's very difficult to reason about code, and things are generally defined by convention, until they're not. The callback is generally the last argument passed to a function, except in async control functions where it's the second to last one, and the last one is an array of the results of previous clauses.

Saying that using the same language for the front-end and back-end allows engineers to work on both parts is silly, IMO, as front-end and back-end work require two disjoint skill sets. Just because surgeons and chefs both use knives, it doesn't mean that you'd want a chef performing a liver transplant. Also, node.js actually reads a lot more differently than most front-end code I've seen. Back-end code written in Java and front-end code written in Javascript tend to have the same sort of data flow and control structure, as opposed to Node which is on an island all by itself. I could go on further, but you get the gist.

Re:Hard-won lessons: Five years with Node.js by porker on Thursday April 20, 2017 @03:50AM (#14154731)
> Stack traces are useless. Yes, this function got called with invalid argument values from the event loop. What function called it, and what arguments did it have?

Good it's not just me. Working in TypeScript I find it even worse; sometimes the stack trace uses my .map files and other times the compiled JS file features in the stack trace.

> Javascript itself basically has objects that are just JSON objects. When you're passing them back and forth, you get the irresistible urge to add "optional" fields just to pass one extra parameter for a use case. You generally end up with a big ball of wax parameter object being passed around with fields with unclear purposes.

This. Working browser-side I find it gets even worse when you don't want a pure data object but to add methods - but somewhere down the line the object gets persisted to localStorage. Not a JS problem, a problem with storage in any language - but because a Class and a data object are interchangeable, I see it happen more than usual (and cause unexpected bugs)

Re:Hard-won lessons: Five years with Node.js by nawgszy on Thursday April 20, 2017 @04:12AM (#14154821)
>For large production systems that need to be supported and maintained, it's awful

I don't think it's changing as quickly as you say, especially over the time since ES6 released/acquired first-class support, but you are right, this has been an issue.

>Javascript itself basically has objects that are just JSON objects. When you're passing them back and forth, you get the irresistible urge to add "optional" fields...

You use classes incorrectly / refuse to use classes and then complain when they don't behave like classes?

And then you blame the language?

Honestly, your two points preceding this were pretty reasonable. But I really think your bias starts to show yourself in the next ones.

>Libraries are often half-baked

You're really going to need to flesh this one out. React is half-baked, and so is the create-react-app surrounding it? Express is half-baked? Loopback is half-baked?

I won't deny shitty packages exist; Javascript has a low barrier to entry, and things can be mildly functional and kinda broken pretty easily. But I mean, it's obvious which packages don't suck if you just look at the amount they've been downloaded off npm and their issue lists on github.

>I can't stand NPM. A lot of times, two libraries that you want to include will depend on incompatible versions of another, shared library

In the last 18 months of developing in Node.js, I have not run into this issue once. Before that, sure, but I don't really see that as an issue lately.

>It's very difficult to reason about code

Promises or async/await fix all those issues. Again, this seems like a complaint 18 months out of date

There's issues with JS as a backend, to be certain. It's not nearly as performant as Java/Go/whatever language you fancy is capable of and it's single-threaded.

However, I don't think it's changing as rapidly as you think lately. I honestly must say that you sound like you had the issues of 2 years ago that have been improved on a lot by ES6 and a little maturation of the ecosystem.

The language is very flexible, and that definitely lent itself to a rapidly changing ecosystem at first. But if you want to take that flexibility and see how far you can bend it, then complain when it breaks, it's not a good look for a criticism of the language.

Anyways, this is a strangely impassioned defence, which I guess stemmed from the fact that your first two points resonated with me, but then your following points came up a bit short. I think you maybe haven't looked on the language with fresh eyes for a while, and will find it is not quite as easy to criticize these days.

Re:Hard-won lessons: Five years with Node.js by jimmywanger on Thursday April 20, 2017 @08:07AM (#14155892)
> I think you maybe haven't looked on the language with fresh eyes for a while

I'm working on a very old node codebase - it's over 3 years old, which is absolutely ancient in terms of node and the pace of its development.

And you're correct, we're not using classes, promises, or async/await. However, this being a large system that's in production, we don't exactly have time to rewrite everything to take advantage of new features, and introducing another way to do something when we already have 5 ways of doing the same thing that are different with nuances seems silly.

And refactoring a dynamic language is just orders of magnitude harder than refactoring a static language. With a compiler, you have reasonable confidence that you've found every use of a particular function or field. With dynamic languages, you're never quite sure, especially with Javascript.

That's why I said that for a long-running production system, I would advise against Node. I'm sure something else would come down the pipe that would fix your particular complaint, but might introduce one of its own. And once you already have a large mass of code, you're sort of stuck with that version unless you have time to do a complete rewrite with the new coding paradigms that might introduce bugs. Heck, we tried to just use the latest version of Node, and all of our tests passed. When we tried to deploy it to production, we had to hastily roll back because it started sigseving after a while under load.

One of the largest advantages that people tout for node is that it's easy to write large quantities of code for. But that's also a curse for stuff you have to maintain, as it almost seems like you're taking a snapshot of the Node ecosystem at the time that you start writing the program, and it's extremely hard to update/upgrade it. Hence my dislike of it for any sort of long-lived production system.

EDIT: for an example for half baked node libraries, let's take a look at handling command line arguments. The two leading contenders are minimist and commander. Minimist gives you very few features, as befits its name. Fine. But if you want anything with more feature, you get to use commander. Commander doesn't really handle required arguments properly, always uses -h as a flag to trigger help (not configurable), and when you pass in two strings as flags to set the value of a named variable, it always sets the value of the one that's listed last. (e.g, if you want -version and -ver to indicate the same flag, the library parses what you pass into it but only sets the -ver variable when it parses things). And this is the second most used command line parsing library in node, as far as I can tell.