Hacker News new | past | comments | ask | show | jobs | submit login
Hard-won lessons: Five years with Node.js (scottnonnenberg.com)
340 points by ingve on April 19, 2017 | hide | past | favorite | 356 comments



I can't imagine choosing to write Javascript on the server, but considering its popularity I'm wondering if I'm wrong. So I'm curious as to the reasons people chose Node.js and whether you would recommend it, anybody willing to share their experiences?


V8 is a world class compiler. Compared to ruby, Python, Erlang, php and that ilk it is lightning quick. (Pypy is a good match for it but it's not main street and you can't just use any module.) in terms of performance and popularity, v8/node stand pretty much alone as far as dynamic non-compiled environments.

JavaScript has a lighter weight feel than Java and the jvm stack. Single threaded with a top notch event reactor. You can write just a few lines in node and have a web server serving some json.

There are a ton of JavaScript coders. There is something to be said for having a common technology throughout your stack and you ui is almost certainly in js.

It's easy to get something simple going quickly, there are tons of libraries and you're going to need to write go, Java or .net to out perform it.

The big downsides, imho, v8 is designed for client side stuff. Both it and dart vm are limited to relatively small memory footprints (think 1GB) which just isn't good for some workloads and problems. Likewise a lot of server tasks can make good use of real threads, you're out of luck with node, you can have child processes and send messages but if they have to share big amounts of data the marshaling becomes a bit of a bottleneck. If you work is database crud, or light weight, or horizontally scalable, or able to be modeled as streams then node isn't that bad. Js feels kind of limited in how certain things are modeled, there isn't much data hiding or abstraction; the extreme simplicity almost creates more complexity for some things. There are lots of different opinions on basic code behavior, some node modules do work on import, some need explicit initialization, some alter prototypes and it's a concept that seems to be lost on many js devs; I've burnt hours debugging something because someone reordered the imports and it screwed init logic. And you'll completely screw yourself if you don't stay up to date with your depends, things change fast and sometimes they change a lot. Both node and dart vm seem really well equipped for tooling type things that are usually done in bash, Python or perl but that doesn't seem to be as popular.

It's definitely not for everything but it's worth a look. It is really popular.


> Compared to ruby, Python, Erlang, php and that ilk it is lightning quick.

Ain't nobody is going to compare performance against Erlang for numerical number crunch.

It was never built for that. It's not even a fair comparison.

It's like comparing a race car against a hybrid prius and saying the race car suck at mpg. They're built for different purposes.

Ilk implies as if Erlang is some crap flavor flav tech. It is not.

Erlang was made for concurrency.

NodeJS was made to solve for concurrency too.

And Erlang beats NodeJS hands down in concurrency.

The actor model is a much better model to do concurrency and preemptive scheduling is amazing. It's easier to mentally think about actor and the code isolation in each processes makes it much more cleaner, object oriented, quoted by Alan Kay himself.

NodeJS chose some existing language to do concurrency where as Erlang was created from the ground up to do concurrency. Hence the reason why it's VM is so amazing on top of the fact that concurrency constructs are first class and primitives.


>It was never built for that. It's not even a fair comparison.

No, but it means I can write relatively computationally intensive server side code in JavaScript rather than having to switch to C and use an FFI. It's always nice to have decent performance, even if it's irrelevant most of the time for web programming.

Erlang is great but its ecosystem is tiny compared to Node's, and as a programming language it's at least as quirky as JavaScript.


> Erlang is great but its ecosystem is tiny compared to Node's, and as a programming language it's at least as quirky as JavaScript.

I disagree with this; while the syntax is unusual for many, its semantics are extremely simple and clear. I don't think it has anything quite like:

* JavaScript having `null` and `undefined`. * JavaScript lacking have proper integers. * JavaScript strings being UTF-16, so things like "".length don't work. * Scoping of 'this'. * The unmanageable automatic typecast rules * Semicolon insertion. * JavaScript `with (x) {` (maybe a cheap shot since it's so uncommon, but we are talking about language design).

Main quirks I can think of for Erlang are when people trip up over "strings", <<"binaries">>, and iolists. But I'd love to hear where others run into proper semantic quirks.


Does it have a non-hacky way of handling record types yet?


It has maps now! This chapter speaks of them being fully supported in future versions, which have since arrived. http://learnyousomeerlang.com/maps

And even records are hardly a quirk like the ones I listed for JavaScript: as long as you remember that they're just syntax around tuples, you're hardly ever surprised by what they do. You'll never get a runtime behavior you didn't expect.


That is definitely an improvement, although the document you linked to suggests that the old-style records would still be used for some purposes. If the language already has tuples there's really no reason why it shouldn't just have tuples with a fixed set of named fields.

The quirks of JavaScript that you mention never bother me at all in practice (and yes, bringing up 'with' is a very cheap shot, and Erlang's string handling is pretty wacky too), but I remember that not having real record types was a serious pain point.


Erlang/OTP as a system blows away anything in node camp, and is only really approached (but not eclipsed by) by the JVM. Supervision trees in particular I have seen poorly reimplemented over and over in Go, Java, Python, and so on. It really feels like a well polished system.


The only difference, of course, is that nobody uses Erlang.


> Both it and dart vm are limited to relatively small memory footprints (think 1GB) which just isn't good for some workloads and problems.

This hasn't been true for a while now.

node --max-old-space-size=8192 server.js

See also http://prestonparry.com/articles/IncreaseNodeJSMemorySize/


How about using 64gb?


> V8 is a world class compiler. Compared to ruby, Python, Erlang, php and that ilk it is lightning quick.

I've heard that a lot but advocacy always seems to be based on artificial benchmarks. Most server apps are I/O bound and the ones which aren't tend to bottleneck in native code – i.e. a gzip implementation would run faster in V8 than python, ruby, etc. but since they're just calling a C library, it's a question of whether V8 is faster than GCC/Clang.

One area where this is more interesting is async support, but the argument then is that it's easier to write async code in JS than other languages and reasonable people disagree on that point.

I'm not saying that V8 isn't an impressive bit of work, just that most of the advocacy I've seen has reminded me of the JVM hype cycle before most people learned that a JIT mattered a lot less than their architectural choices.


I see some merits. I am not sure I buy using JavaScript based on performance/dev speed ratio though. Lua is even faster, lighter weight and has clean, logical semantics. I guess I'm just trying to decide if having a large talent pool and tons of modules is good enough.


I would watch it with that "large talent pool". As is typical in the language du jour, there are tons of worthless imposters going around selling Node.js skills. However, it's even worse in the case of JavaScript because since it uses the "same language", some people assume that light front-end scripting qualifies as real backend development experience.

"Tons of modules" is also a misnomer, because a much larger than normal portion of these are low-quality, small, and/or poorly maintained. Just the way it goes in the age of GitHub, where everyone wants a badge of honor in their repo list.


> there are tons of worthless imposters going around selling Node.js skills. However, it's even worse in the case of JavaScript because since it uses the "same language", some people assume that light front-end scripting qualifies as real backend development experience.

Seconded.

I'm working for a company building an Ionic app, and they hired two junior programmers with "angular experience" (both of whom had built angular apps before) to be the developers on the project.

I'd used KnockoutJS but never ES6, Angular (1 or 2), TypeScript, written a mobile app, plus the RxJS concept was new to me, as was thinking asynchronously (I told them I wasn't a good fit for the project).

Yet while the developers have struggled to do their work and the schedule has slipped, I've been able to pick up the concepts, write half the app and solve the juniors' problems despite my unfamiliarity with it all.

Glad to see nearly 20 years' experience programming makes a difference, even though none of it was with today's "hot" technologies.


similar experience with ionic. yeah, I don't know 'angular' (well, didn't) but have still been able to be very productive very quickly (20+ years as well).

and... the 'impostor' thing... quite true. easier for these people to slip in to larger companies, I think, but it's a problem all around.

I would expect someone with 20+ years of experience to be able to help juniors troubleshoot in any language/stack, though, whether they expect it or not. :)


> I would expect someone with 20+ years of experience to be able to help juniors troubleshoot in any language/stack, though, whether they expect it or not. :)

I can with one, and have cracked his management style too, so he's gone from being unproductive and the butt of office gossip to meeting schedules.

The other is new to this country, doesn't speak much English (e.g. not enough to ask questions) and understands little English too. At a loss for how to proceed...


I've had some trouble finding explicit node backend jobs, as someone who'd consider themselves a relative specialist in it. Most places want a full stack developer well versed in common frontend frameworks and maybe a tiny bit of services on the backend. Most backend focused jobs (rightly, probably) focus on more traditional stacks or go. There's amazing things one can do very quickly with node exp (serverless/Faas services for one) but I've been struggling to find positions reliably.


Same, almost all JavaScript job postings are front end only. It's quite a shame.


"if you don't stay up to date with your depends, things change fast and sometimes they change a lot."

This, was actually one of the things I liked most about Node.js - npm allows a developer to specify all dependencies (`pacakage.json`), versioned, similarly to maven but not as clunky. I was able to get up to speed project very quickly and easily using just `npm install`. I had one or two versioning issues to iron out, but the advice it provides about what is broken and where was very helpful.


Not sure what your other experience is, but most dynamic languages have simple package management platforms similar to npm. As you note, Java has Maven/Ant and C# has NuGet, both of which are substantially more "enterprisey".

It'd be interesting to hear a fair, modern comparison between npm, ruby-gems, LuaRocks, pip/PyPI/cheeseshop, and the other big ones I'm sure I'm forgetting.

The JavaScript community has had a lot of competitors on this front, particularly for frontend asset management, but it does finally seem to stabilizing a little bit. It took forever.


A "Battle of the dependency managers" if you will .. sounds great!

I mentioned NPM in particular in the context of this being a node.js discussion. I've seen a few comparable tools in my time but IMHO NPM may be one of the cleanest, considering this as a feature of node.js - it does add to its attractiveness as a development environment.

Yeah it took the JS community ages to sort this out, but in NPM there seems to be an answer.


> V8 is a world class compiler. Compared to ruby, Python, Erlang, php and that ilk it is lightning quick.

Not to nitpick details, but V8 is a runtime, not a compiler.

A compiler checks your code and tells you if it contains errors before you run it. V8 does not.


V8 is a JIT compiler, which incorporates a runtime and a compiler.


> V8 is a JIT compiler, which incorporates a runtime and a compiler.

So it's a compiler which incorporates a compiler? Compilerception much?

Seriously though: Can I tell V8 to compile my JS and tell me any errors found before I deploy it to production and runtime? Yes or no?

Just because V8 internally JIT-compiles the JS-code to something eventually executable which the machine can run doesn't change the fact that it's interpreter and execution-engine (also known as a "runtime") for Javascript code.

Just like Python and all those other platforms you listed as not being "compilers" (in which case you're absolutely right).


> So it's a compiler which incorporates a compiler? Compilerception much?

No, what I meant is that the concept of a JIT compiler incorporates both a runtime and a compiler.

> Seriously though: Can I tell V8 to compile my JS and tell me any errors found before I deploy it to production and runtime? Yes or no?

That's not the job of a compiler. It's a feature of compilation, but a compiler does not by definition have to compile your code before deployment. What would you be compiling the JS to? If you're wanting to check your syntax, your IDE should be able to do that, or you can use a compile-to-JS language like TypeScript. Yes, it's dumb I know - that's one of the many reasons I use TypeScript.

> Just because V8 internally JIT-compiles the JS-code to something eventually executable which the machine can run doesn't change the fact that it's interpreter and execution-engine (also known as a "runtime") for Javascript code.

You seem to be hung up on the idea of a compiler as something that checks your code is correct. It isn't - that functionality is incidental to the compiler's job, because it can't translate invalid syntax into whatever destination language it compiles to.

> Just like Python and all those other platforms you listed as not being "compilers" (in which case you're absolutely right).

I did no such thing. That was someone else. Any language which internally uses a bytecode representation is a JIT compiler, including Python, Java, and PHP. You could argue I'm being nitpicky, given that pretty much all performant interpreted languages use a bytecode representation - it's true in a sense, but I'm just trying to highlight that you seem to have a misunderstanding of what a compiler's job is.


"but a compiler does not by definition have to compile your code before deployment" Huh?

Not sure many experienced developers would agree with you a JIT Compiler is quite different to a real compiled language C Fortran Etc


a compiled language, yes. But the function of a compiler, between a compiled language and an interpreted language, remains the same. It translates code from one representation to another.


This is really simple. Do you use V8 to compile your code or to run it?

Just because V8 has a compiler, doesn't make it a compiler. Do you see the difference?


V8 compiles code into bytecode and runs that. This is really simple.

V8 is a JIT compiler. It both compiles code and runs it. For your original complaint about not being able to compile JS up front, you're talking about Ahead-Of-Time (AOT) compilation. You don't seem very familiar with the relevant terminology.

In fact, I just looked it up and apparently V8 compiles JS directly to machine code rather than bytecode: https://en.wikipedia.org/wiki/Chrome_V8.


V8 compiles to native code with the exception of low memory devices (512M or less), for which it has a (relatively recently introduced) bytecode compiler, so it uses an interpreter in that one case.


Syntax errors will be detected prior to runtime because the application will not be able to be compiled into whatever format it compiles down to (raw ASM, some IR, etc.). A fully AOT compiler will generally check more than a JIT compiler, but there is still compilation and it is still a "compiler" in a technical sense.

And for the record, AOT languages also have "runtimes" provided by a platform. If someone combined gcc and glibc, would the combined product no longer be considered a "compiler"?


It is my understanding that V8 provides you with the capability to interpret your code and run it, while gcc produces a resulting binary which be run independently of gcc.

Can V8 be used to compile js to a artifact/binary which can later be executed independently of V8? If no, then it's not a compiler. It's as simple as that.


Executables from gcc can't be run independent of a binary-compatible C runtime.

The difference is just that V8 includes the runtime and compiler in the same program. If they split it into v8c and v8lib without making any changes to the way that JavaScript is converted into something that your CPU processes, would it then be a "real compiler"?

Are mcs or javac real compilers? They both leave behind an "executable", but they require a separate runtime to be installed actually execute it. What about GCJ? What about anything that compiles down to LLVM IR and depends on LLVM to convert it to machine code? Is that not a real compiler either? Is CPython a compiler? It leaves junk on my disk in the form of pyc files.

I'm really curious why you insist that something isn't performing compilation if it doesn't write its output to disk. When is the process of compiling from one target into another not compilation?

Perhaps you're suggesting that only compilers that emit appropriate machine code are "real compilers". That's silly, but I could understand if that's what you mean.

However, I think you'll be disappointed to learn that V8 does directly emit machine code. [0]

[0] https://github.com/v8/v8/tree/master/src/compiler


There is no interpretation involved; V8 has an unoptimized base compiler for compiling JS to machine code one function at a time, and a pair of optimizing compilers that work based on runtime profiling. V8 also has a bytecode interpreter for low memory devices, but it'd mainly be used on very low end mobile devices.


- Node wasn't designed for CPU intensive work, it's primarily for IO based work, which it frankly excels at, in terms of speed and scalability.

- To get around the 1GB cap use Buffers, they are outside the v8 heap.


I've got over a decade of professional experience in C#, Python, and Java. I'd consider myself a Java developer before all else, yet I still turn to Node.js for proof of concept projects because certain things are just quicker to implement.

Here's the major caveat, out of, say 100+ PoC/prototype projects I've ever done, I've taken two to 'production'. I put production in quotes because they were actually internal services as part of our build and delivery pipeline. It's a major pain in the butt to monitor and keep Node.js running production-like in even remotely similar ways you would with Java, .NET, Python, or even PHP for that matter. I don't expect such drastically different technologies to be exactly alike for production workloads, but there's usually analogous ways to do X, Y, or Z.

You know where Node has been awesome? You land a project with a real tight deadline and its more of a fire and forget project (think interactive 'experience' at a major gaming conference for instance). It needs to run pretty well for a short period of time with a narrow scope of functionality, but some of that functionality is non-trivial. I absolutely love Node for that.


I've had several experiences with Node.js contractors handing over "finished" applications that were only configured to run under webpack-dev-server[0]

It clearly tells you in the README it's not for production, but I have this recurrent discussion with developers who tell me they have only ever run Node.js this way.

What that tells me is there is quite a trend a towards exactly what you describe, where a lot of what gets written never goes into production.

[0] https://github.com/webpack/webpack-dev-server


Webpack dev server simply serves up compiled assets for convenience, because it serves new assets as they are compiled and blocks when compiling. It should be fairly trivial to serve up static production assets as needed. I say this as a person who just converted a production rails app to use webpack as first class citizen.


> in the README [that it is] not for production but ... who tell me they have only ever run Node.js this way. What that tells me is there is quite a trend towards ... a lot of what gets written never goes into production.

No, it is worse than that I would have thought. The cynic in me (who is more often right then wrong) suggests that is means there is a lot of "proof of concept" level of code out there in production environments potentially running important things.


> yet I still turn to Node.js for proof of concept projects because certain things are just quicker to implement.

Why?

Writing Java is really very fast these days, especially with IDE's.

I can get a small web site serving JSON REST requests and memcache up in ten minutes with a simple Maven/Gradle build and full IDE integration.


You know what isn't as quick? Websockets, non-trivial asynchronous code, boilerplate, and build times. The vast majority of my company is built on Java and we're not encumbered by legacy code, so we get to play with all the new stuff. I don't need to be convinced that Java (or even more specifically the JVM) is a good choice for many practical reasons. I live in IntelliJ and Gradle (and Maven too) all day, you're preaching to the choir.

Between having a REPL, near instaneous stop/relaunch times, and doing in 8 lines of Node.js what takes me 70 lines using CompletableFutures, I'm still going to reach for Node to prove the idea.

Now, when it takes hold and looks like it might stick around, it immediately gets turned into a Java project. Or, if the event we were building for is over, it basically just gets deleted- which pretty much says it all in my opinion.

It's not a toy language, there's some real usefulness to it, but just like anything else, there's a time and place. Currently, that place is NOT production.


I agree that Java's async support is bad (haven't had to use it much since I've been primarily Scala for years now), but I'm surprised a PoC would need to be async in the first place? Conventional one-thread-per-request is fine for non-prod, no?


A lot of projects my team did at my last company were of the "You've got 2 or 3 weeks to build this awesome thing for a launch event that will have a crushing wave of usage for about 3-7 days".

It was really fun work, because even the 'simple' stuff we built had to address some of the big traffic issues you'd normally have at a much larger scale and the work was usually very high concept or cutting edge. It would've been a nightmare to maintain for longer than a week though.


I'm surprised that you consider it controversial that a highly dynamic language can be considered fast to PoC something in than Java. There is just less typing/code that needs to be defined (I know IDEs help). Also easier to do quick and dirty stuff that I imagine would be more restricted in Java. No classes to define, just throw your values in there.

I prefer python in general but for zero-to-simple-web-endpoint I may pick Node.


> I'm surprised that you consider it controversial that a highly dynamic language can be considered fast to PoC something in than Java.

Sure, but that wasn't the argument; GP talked specifically about async and websockets, which are areas where Java is particularly weak, but areas that I was surprised would be required for a PoC at all.


Fair enough. I was mostly responding to the thread of discussion overall. I realise now that I was probably reacting more to the viewpoint of hota_mazi.


Do you have any particular reasons to prefer Node (assuming Javascript) to Clojure/Groovy?

Asking, because I do most of my development in Clojure and find it much nicer than Node both for POC and production. There's also self-hosted Clojurescript now that runs without a dependency on JVM.


Honestly, because I'm pretty good w/ Node (or just JS in general) and haven't invested the time to get good w/ Groovy or Clojure at this point.

I've only just played around with Clojure and I've written a middling amount of Groovy, but the vast majority of it involved Jenkins build pipelines, so I don't really count it.


> I can get a small web site serving JSON REST requests and memcache up in ten minutes with a simple Maven/Gradle build and full IDE integration

Java guys always say how they have really developed tooling and look down on other languages. The problem is those nice tools have become a hindrance as well. You can't develop in Java/Kotlin if you don't use those huge complicated tools.

I can't speak for all, but at least for me it prevents me from ever using Java tech. I can develop just fine using a lightweight editor in any of the languages I use. I don't need huge tools or complicated build systems. Because my languages have nice tooling that I can write manually and fully understand.

I tried using Kotlin and step one is always install Intellij.


> huge complicated tools.

Oh please. Let's be real, Maven is not even remotely more complicated than the typical package.json, webpack.config.json, .babelrc triple you need for any useful NodeJS project (though you can put the .babelrc into the package.json, I've heard that's the way to do it at the moment). I was so taken back that nowadays JS needs a build step too. But it's a "transpiler", not a "compiler" - cause that's something completely different.

> I tried using Kotlin and step one is always install Intellij.

So? Atom and Visual Studio Code did need to be installed too on my machine. This mentality reminds me of someone using an axe head as a hammer "I'd have to pull the hammer out of the toolbox" (install it) - that's too complicated, I prefer light-weight tools!"


No I want to use the command line.

https://maven.apache.org/guides/getting-started/maven-in-fiv...

Maven quick start first command:

> mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Then it generates stupidly deep Java structure.

and next you have to write a verbose xml. They even say:

> The POM is huge and can be daunting in its complexity

All of this stuff is verbose and built to be generated by IDEs. It's not clear, it's not concise.


> Then it generates stupidly deep Java structure.

It generates enough structure to scale up to reasonable projects. The nesting is a price well worth paying for consistency. Every maven project puts its source in the same structure, with the result that you can jump into any project and know how its build will work and where to find the source.

> All of this stuff is verbose and built to be generated by IDEs. It's not clear, it's not concise.

Verbose is worth it for clarity, particularly in a file you edit rarely. It may not be concise but it absolutely is clear, as the example from your own link shows.


I'm sure the tooling is useful and a lot of it reasonable. I've never approached a Java project that I did not find intimidating, either Android with all the Gradles and XML.

I've never seen a barebones project as you would when using just node+npm without all the extra tooling (webpack and friends). Node+npm is to me as simple as python+pip. Is there a natural counterpart, Java+maven or something?

And to be fair. All my attempts at approaching webpack have been even worse. And most JS-framework seed projects are similarly complex and automagical.


I don't think you need anything other than java+maven. That's all my projects use as far as I'm aware. Android probably requires some additional stuff for its packaging but I just enabled the maven android plugin and trusted that to handle it - if there's any other config I haven't been touching it.

The grandparent linked to the maven getting started, https://maven.apache.org/guides/getting-started/maven-in-fiv... . That shows what the minimum looks like - a pom.xml, and application source code in src/main/java (under its package structure). (The unit test isn't strictly necessary but is good practice).

The pom's XML header and modelVersion are boilerplate, but the rest is pretty clear and self-explanatory (though admittedly verbose).

At that point for a library project you're sorted, for an application you can run your program via "mvn exec:java" which is adequate for development. To actually package up your application for distribution you probably want to use the shade plugin a la https://maven.apache.org/plugins/maven-shade-plugin/examples... , but that's something you'd do as part of "productionisation". (Back when I worked at an early-stage startup we had things running and serving user requests via "mvn exec:java")


Appreciate the overview. It sounds similar to what I'm used to but, as you say, perhaps a bit more verbose. And some stuff is non-obvious to me, such as mvn exec:java instead of my-java-runtime main.java or whatever.

I've encountered a bit of this with most AOT-compiled stuff except for Go. Make or compiler-flags also requires a bit of learning to get going.

Most dynamic languages tend to be more straight-forward with this.


> some stuff is non-obvious to me, such as mvn exec:java instead of my-java-runtime main.java or whatever.

That's kind of our way to do virtualenv-like functionality, which is mandatory rather than optional. (Or you can specify the classpath manually in the same way you would for the pythonpath, but no-one wants to do that). IMO that's the right thing - having libraries installed in my system python has only ever caused trouble in the long- or even medium-term, even if it makes "hello world" use of libraries very slightly simpler.

There's probably a way to get a shell with the classpath set up correctly, but I always found that kind of modalness more confusing than helpful.

> I've encountered a bit of this with most AOT-compiled stuff except for Go. Make or compiler-flags also requires a bit of learning to get going.

In my experience it does all work without any flags or extra knowledge. "mvn" is the entry point for all the things you want to do - you don't ever have to know that there's a "java" and "javac" underlying it.


> It generates enough structure to scale up to reasonable projects.

It generates stupidly deep structure because Java requires a stupidly deep structure.

> Every maven project puts its source in the same structure, with the result that you can jump into any project and know how its build will work and where to find the source.

Rust, Elixir and Erlang achieve this with tooling that is practically trivial to use. Without an IDE.

> Verbose is worth it for clarity, particularly in a file you edit rarely.

Being concise is a big factor in clarity.


> It generates stupidly deep structure because Java requires a stupidly deep structure.

All of the depth is useful. The folder structure corresponding to the package structure makes it much easier to find the source for something.

> Being concise is a big factor in clarity.

True when there is large-scale structure that varies for the reader to comprehend. Less important in an inert declarative structure. Again, look to the example you linked.


> The POM is huge and can be daunting in its complexity

Because they are honest. Maybe it is because I'm more accustomed to poms, but the package.json/babelrc mix and webpack.config.jsons are daunting to me too.


Web ecosystem is a mess as well. What I meant was Rust, Elixir, Erlang build/project files. Those are trivial.


Maven is a "bad example" - it's horrible. Everybody agrees.


> mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Ah, I can see how this is much more complicated than the good old

    npm install webpack babel-loader babel-core babel-preset-es2015 babel-preset-react --save-dev


You don't have to use maven directly. Something like https://github.com/bodar/jcompilo would be much simpler and faster for a small project.


You don't need a build step for Node.js, 93% of ES6 features are already included in the latest version. Babel is more for client side than anything and that's because browser vendors take a while to implement new standards, so yeah JS has unique challenges and constraints as the de facto language of the web.


Or typescript frequently.


> So? Atom and Visual Studio Code did need to be installed too on my machine. This mentality reminds me of someone using an axe head as a hammer "I'd have to pull the hammer out of the toolbox" (install it) - that's too complicated, I prefer light-weight tools!"

You misunderstand my point completely. I was trying to say the Java ecosystem is complicated and the only way it works is by using large IDEs. Saying how awesome Java IDEs are is disingenuous because Java is unusable without them.


> because Java is unusable without them

This is like saying 'Javascript is unusable without IDEs', you know.


And this is making Java look good how exactly?


This makes all programmers liking to write code with maximum level of comfort - e.g. using IDEs.


Most Java people I know use IDEs mostly just to edit and debug the code, and does the builds/runs/tests from the command line.


What do you mean with "just to edit"? Aren't there any (compilation) errors, warnings displayed anywhere?


Yeah there are, sorry, a this point I consider them basically auxiliary editor features. I forgot that some other languages don't have this luxury.


Getting a node server running the first time is actually very difficult. The libraries constantly change so fast tutorials frequently don't work. It was easy once I understood everything, but it wasn't easy the first time at all.


IntelliJ is an awesome IDE, but it's not necessary. Part of it is Kotlin as well though, that's definitely as immature (as in age and mindshare, not attitude) of an ecosystem as there is with Java.

The thing with Java is the amount of boilerplate, but the thing with Java is that all of that is ridiculously well documented or demonstrated ad nauseum. Are you building a jar with Maven? Your folder structure looks like this. War? It looks like that. Before Yeoman or any other generators even existed Maven has had archetypes that do the exact same thing.

If you compare Maven, heck, even Gradle to Webpack + Babel for even fairly trivial projects, there's no way that it's more complicated. The tools for Java are truly portable, I can't even recall the hell we used to have to go through when we had to run gulp builds on Windows because developers of various libraries had hard coded *nix style paths, etc.

Most importantly, Maven and Java really aren't a moving target. 9 months from now I'm not going to have to overhaul my entire build process because a wide swath of my plugins have completely changed directions. Stability is how you wind up with the time to make things run smoother in production. It's how you wind up with repeatable patterns and better instrumentation. You get a chance to take a breath and formulate an honest to goodness process vs. literally sprinting as fast as you can to simply keep up with the changes.


> You can't develop in Java/Kotlin if you don't use those huge complicated tools.

This is based on what? It is totally untrue from my experience. Quite the opposite.


I tried following the gradle command line guide for Kotlin to build a project and it did not work and I had no idea why. No errors and nothing happened.


The edit/refresh cycle starts to slow as the project grows in Java, but node has pretty close to zero startup time and is interpreted. That plus a repl supports a much more explorative coding style where things work as fast as you can add them. No JVM restarts, compilations, or going back to change types or api's in the middle of a thought.


> The edit/refresh cycle starts to slow

IDEA and Eclipse compile your code as you write it. And with Hotswap, you don't even need to redeploy anything. They also all offer REPL's that are much more sophisticated than anything Javascript has to offer.

I think you haven't used a JVM language and its ecosystem in a very long time.


> And with Hotswap, you don't even need to redeploy anything.

Except when you have to restart the JVM because you added a class or a whole bunch of other things that it can't hotswap in the new code.


It's true that the hotswap support built in to the JVM is somewhat limited, but there are tools that are more comprehensive and can hotswap new classes, methods, method signature changes, etc. (JRebel and spring-loaded are the ones that come to mind).


Still better than any dynamically typed language (I mean any) where you always have to redeploy everything since none of these language support incremental compilation, let alone incremental reloading.


If I'm using a truly compiled language (eg. C++, D), which have incremental compilation, I still have to redeploy everything since 'everything' is a single executable.

If I'm using an interpreted language I only have to deploy the changed source files. Git can do that for you.


I use Java today daily, and came from Node. It is slower to have the compile step, even on very powerful machines, dynamic types are faster to change, and there are many caveats to hot reload. The repl comment was about is about speed, not sophistication. When something happens instantly versus a tiny pause, you don't think about seeing your change immediately on save, versus batching many changes together and then testing them. This turns out to be faster for me for explorative work. Many people agree. Just trying to explain. /shrug


I've found myself getting much better at making testing changes in such a way they can be hotswapped, then batching them up into a change when it's necessary to do a JVM restart. Sometimes I impress myself with how long I can go with just hotswaps, kind of like a code golf, but it's absolutely the biggest time suck of a Java developer's day. Besides meetings.


> I can get a small web site serving JSON REST requests and memcache up in ten minutes with a simple Maven/Gradle build and full IDE integration.

Dropwizard is a great example of this. It's an opinionated (convention over configuration) Java framework for building REST web services. You can get a 'Hello World' web service up and running in literally 10 minutes following this tutorial http://www.dropwizard.io/1.0.0/docs/getting-started.html


I can understand it. If you want to just get something together quickly then dynamic languages do have an edge. They allow you to say "just give me whatever and if it fits, it fits" and if you aren't that concerned about it breaking you can build something extremely fast.


You're just repeating the same claim without any evidence.

Why is it faster to write code in a dynamically typed language?

Most modern statically typed languages have type inference so you don't even need to write type annotations for the most part, assuming these extra characters were the reason.

So what's that mysterious reason that makes writing dynamically typed language faster?


You're leaving out a lot when you say it'd take you "five minutes with a simple Maven/Gradle build". What's a maven? What's gradle? What's groovy and where can I learn it?

I literally don't know the answers to these questions so the same task would take me hours, possibly days. Getting from zero to JSON api in node.js is fast by comparison.

Note I am not arguing whether or not it's better in the long run to be the guy that went from zero to node.js or zero to Java, that's a separate discussion.


> You're leaving out a lot when you say it'd take you "five minutes with a simple Maven/Gradle build". What's a maven? What's gradle? What's groovy and where can I learn it?

You have similar concerns with node (What's npm? etc...) These are peripheral and necessary knowledge on both platforms.

> Getting from zero to JSON api in node.js is fast by comparison

It's only fast because you already have the knowledge.

Two equally proficient developers in Java and node will set up and get a server up and running in about the same amount of time.

The idea that it's a faster to achieve in a dynamically typed language is a myth.


> It's only fast because you already have the knowledge.

No, when I said "from zero" I meant from zero knowledge.

> You have similar concerns with node (What's npm? etc...)

What's the "etc..."? Install node and you get npm with it.

Writing a REST service IS simpler with Node when going from zero, I know because I have done (or at least attempted) both from zero in the recent past.

> The idea that it's a faster to achieve in a dynamically typed language is a myth.

Doesn't seem like you're open to discussion on this


This is a classic case of you forgetting all the learning and concepts you needed to get to "zero".


I don't think so. Npm is included with node and is very simple to use.


So your main argument is that you have to make two downloads with Java (JDK and Maven) but with Node you need to make one? Seems pretty weak.

It can't be anything else, because after you have Maven, it is literally a single command to set up a REST project using Dropwizard.


Well, to an extent this is a subjective question. With node, you get npm with it, npm is what everyone uses, and npm is clearly what you should be using too. Moreover, the basic functionality of npm is very very easy to understand.

I find the Java ecosystem terrifying by comparison. I have no idea whether Maven is what I should be using or if I should be using something else instead -- having it as a separate download makes a big difference in that regard -- and I have no idea by looking at a typical Maven config file what it does.


You should probably learn to expand your comfort zones more effectively, if the Java ecosystem terrifies you.


It's not a macho thing for me. I use the tools that are easiest to use and do the job. Anyway, I have used a lot of different programming languages, and it's the Java ecosystem specifically that I've always found overwhelming whenever I've tried to dabble with it. So I think the problem is Java, not me.


There's nothing "macho" involved in this, your language describing your own state of mind is inflammatory and (hopefully, for your sake) inaccurate.


You may need to expand your comfort zone with regard to mild hyperbole.


"Terrifying? What if something REALLY happens to you? You used 'terrifying' on the Java ecosystem!"[1]

[1]: http://zenpencils.com/comic/95-louis-c-k-we-dont-think-about...


It's not that it's terrifying. It's just... why make it harder for myself? Even if it's one step (which it isn't), why? If the only reason you can give is I need to expand my comfort zone, sorry, I'll keep my comfort zone small and productivity high.


I wasn't responding to you. The person I responded said, "I find the Java ecosystem terrifying" and I pointed out how silly that statement is.


The command to set up a Dropwizard project according to the getting started guide[0] is:

    mvn archetype:generate -DarchetypeGroupId=io.dropwizard.archetypes -DarchetypeArtifactId=java-simple -DarchetypeVersion=1.0.0
Which spends the first 30 seconds downloading a bunch of stuff before asking you for settings to start off your project. I then read the README it created and ran `mvn clean install` as instructed which started downloads that took 1:40 min only to end in a build failure with multiple large tracebacks.

Running `mvn --help` doesn't help at all and the pom file it creates is 143 lines of hard to read XML.

I've used gradle a little, I'm familiar with bundler/gem, pip, npm and dub. Maven just makes me want to run as far as possible from anything Java related.

[0] http://www.dropwizard.io/1.1.0/docs/getting-started.html


You just described my experience with npm, except there aren't any useful tracebacks, just a note absolving npm of all blame and advising me to contact some random module author.

Edit: and of course with npm the annoying downloads happen every time for each project, instead of once per dependency version...


Not excusing any crashes for npm (having those for any package manager sucks), but `npm init` doesn't download anything or make a project that needs to, it has readable config files and `npm --help` at least gives you a list of commands. A lot of the small stuff goes a long way to making things more approachable.


That's apples and oranges. You would have to set up some Express project or something to do what the Dropwizard archetype is doing.

Also package.json and pom.xml are equally (un)readable. At least Maven project files have a schema to help editors out.


> `npm --help` at least gives you a list of commands

`mvn --help` gives you a list of commands too.


Knowing how to use npm and what packages are useful isn't something that is flashed into your brain when you click download on the Node website.


For example, I've been doing a lot of Rust coding.

The code in question looks like:

    iter.next().ok_or(ErrorKind::NotEnoughArguments.into())?.parse().chain_err(|| "cannot parse argument")?
the compiler responds with cannot infer type information for `_`

the solution is of course to do

   iter.next().ok_or::<Error>(ErrorKind::NotEnoughArguments.into())?.parse().chain_err(|| "cannot parse argument")?
then the type inference is decidable

in a dynamic language, you wouldn't have to worry about this; in fact, you wouldn't need to call .into() either - there's just less typing and compiler errors


>So what's that mysterious reason that makes writing dynamically typed language faster?

Less ceremony.


But no ceremony is necessary in the cases where types can be inferred - and in the cases where types can't be inferred you probably do want to to be explicit about them even in a dynamic language.


It's not just the types, it's the whole APIs, culture etc.

Java, for example, is no picnic, whether it can now infer some types or not.

In Python I don't even need a main().


How is

    if __name__ == "__main__":
        main()
different from a main()?


It's only needed if you're importing the file as a library/module somewhere.


You don't even need that.

  print("hello world")
will run just fine


It's different in that it's optional in Python.


I agree Java is a high-ceremony language, but not all statically typed languages are like that.


The slow part of static languages isn't just typing out the annotations. Its needing to describe the type in the first place, and needing to change that type description if the shape of your data changes. If you want to prototype quickly in a dynamic language, you don't need to mess around with any sort of class description as you decide how you want your program to work.


Said dynamic language, not dynamically typed. Would be surprised if anyone considers Java more productive than Rails, Python (Django, Flask, etc) or Express.


You don't need to wait for them to compile.


Unfortunately, modern JS has Transpilers, which you have to wait for, so no, that's not the case anymore. I have not seen any NodeJS project which didn't have to be transpiled (i.e. compiled to a different JS version).


Totally false. Node.js pre-dates Babel by about 6 years so I wonder how that could possibly be true. Second, most ES6 features are already included natively in latest versions of Node so no need to transpile at all. You can even get async/await out of the box.


No one cares how you wrote 6 years ago, today the way to do it (as I've been told by many people who write NodeJS applications all the time) is to use transpilers. And:

> most ES6 features

Most. Ugly word. Really ugly word.


That's a way to do it. It is not the only way to do it, even if some people do it that way all the time.

I might add a transpiler for Typescript to my stack soon, if that language turns out as pleasant to work with as I've been hearing. If I do, it'll be the first time I use one. And I've been working with Node, in production, since 2013.


Go away. I've invested weeks to learn something which at least resembles NodeJS best practices and now you come along and say "nope, we do it different" ... :(

(That was a joke btw. Thanks for the info. The consensus seemed to be that Babel is the way to go, but if your variant works for you good to hear. I will still stay with it. I like ES6 imports in Node.)


Hey, you do you. I'm just here to say that not everyone agrees, or should, that real-world best practice necessarily involves a giant pile of transpilers and bundlers.


Can you elaborate on the "major pain in the butt to monitor and keep Node.js running production-like" What sorts of issues did you face? Certainly .NET and Java have more tooling, but I haven't noticed a difference between keeping a Node process up as opposed to a Python one. Hard to compare to stateless PHP.


The default behavior for Node when there is an uncaught error is to crash the process, killing all requests in flight. Even if you go out of your way to stop this default behavior, errors still likely leave the process in an inconsistent state. Node can't just unwind a few stack frames like synchronous platforms.

Do you read JSON from ajax post bodies? Do you access fields in that JSON without sanity checking it? Try passing JSON that's missing one of those critical fields (as, say, a griefer might do). What happened to your app?


You nailed it. Three major things I care about for my application:

- Logging

- Metrics/Instrumentation/Tracing (memory usage, transactional performance monitoring, etc)

- Surviving exceptions

All of these are either very immature in Node or simply so far behind they may as well not exist. By nature of running in an application server, you do get a lot of benefits right off the bat for all of those, but even if you're running an executable jar instead of deploying to Tomcat stray exceptions will in almost no cases cause your application to simply die for all requests.

Also, say what you want about the verbose try/catch Exception model, but at least you can count on it. Am I getting an Error in this callback or is an exception going to get thrown? Oh, they leaked an exception when I was prepared to handle an Error and now my entire server is down. Does your process automatically restart? Not likely unless you spent a lot of time hand crafting your service to be daemonized, which is generally FAR beyond the scope of most developers I've met in any language (which also upsets me).


Promises and now async/await go a long way to remedy the discrepancy between synchronous exceptions and asynchronous errors, by helping ensure that they both end up as promise rejections (as long as promises/async functions are your de facto async abstraction) while also being handleable with try/catch. The Koa framework (and in the future Express I believe) is designed around this concept, so middleware-level promise rejections can be handled in a single place, and by default simply produce an HTTP error response. It is a shame that it's going to take a while for the Node stdlib to catch up, however.

Also I thought something like PM2 (https://github.com/Unitech/pm2) or Forever (https://github.com/foreverjs/forever) was pretty much standard for production Node apps?


Spot on! And with node version 8, due out any week, we no longer needs babel on the server when doing async/await/import. It will all be there natively.

We use PM2 in production for web apps, long running processes (console apps with rethinkdb change feeds) and cron to spin up command line apps for data transformations, SaaS integrations, bots and more.

Most of us use VS Code now (I still use Vim)...so yes, having done enterprise work with a full blown IDE and tooling can be very helpful as the Node debugging and profiling experience is not great (but getting a ton better).

In the past we had a ton of C#/.net in production, then Ruby and now JS for the indefinite future. We build things that end up in production for 10 years or more, so having that talent pool to pull from in the future will be great.


If one is spending any time hand-crafting the program to daemonize itself on a Unix or a Unix-alike, one is doing things wrongly. On those operating systems, since the advent of the System Resource Controller in 1992 the right way to write a program that runs under a service manager is to write a program that runs in the normal way. No "daemonization" needed.

* http://jdebp.eu./FGA/unix-daemon-design-mistakes-to-avoid.ht...

* http://jdebp.eu./FGA/systemd-house-of-horror/


I for one consider that a feature - it is easy enough to write bad code in JS as it is, so anything that encourages defensive coding and solid unit/functional tests is very appropriate for this particular language.

A crash certainly draws attention to a problem much better than an error in a log that no one usually looks at.

Yes it's a pain, but you deserve it for writing buggy code and then not catching it in testing (that's what I keep saying to myself, anyway). ;)


That crash, in your high-concurrency environment, produced "bad gateway" responses or closed connections for your users. I'm pretty sure they don't consider this a feature.


If only node had exception handling and functions!


Node has - for me - the same problem as C#. Unchecked exceptions on every corner. You don't even know what can explode until it explodes. And then takes your Node instance down. But I am one of these weirdos who likes checked exceptions in Java, so maybe this is not a problem for others.


The same problem as C#? You're fighting a very old position.

Exception handling in C# is amazingly good, you can't run C# production level apps.

It suffers none of the problems that are being discussed above. All you're doing is confusing the discussion with a view point I haven't heard in a decade.


The default error middleware built into my framework caught it and responded with a 502.


...and almost certainly left a bunch of dangling state in your app that, at best, is a memory leak.


... or almost certainly was correctly dereferenced, logged, and garbage collected.


> The default behavior for Node when there is an uncaught error is to crash the process.

What language doesn't do that?


Love it or not, at least Python has uWSGI, which certainly helps keep things running through errors, and gives you more robust logging at a higher level, etc. if you lose your Node process it's just poof with no guarantees you'll get a good trace to pinpoint the fault.


Huh, that's weird, I've never had a Node process silently die in production without a good trace or robust high level logging. Are you sure you're​ not just making stuff up?


pm2 + newrelic = problem solved?


Or just Systemd


Obviously systemd for keeping processes up, but is there a god way to centralise journald logs in one place (and search it). Hoping for something that's pure journald not a syslog equivalent (as I'd rather less software than more).


I'm the biggest JS-on-the-server sceptic of them all, given my past experiences. But this was pre-typescript.

If a TypeScript ORM with automatic schema migrations and decent expressiveness comes around, I'd be willing to give NodeJS another shot.

But so far, nothing comes even close to the productivity of Django + ORM + Django Rest Framework. For your typical CRUD app, this will walk circles around any current JS solution. Even if the lack of static typing eventually becomes a bit of a pain.


Have you seen typeorm? https://github.com/typeorm/typeorm


I have. It's a great improvement over other ORMs in the NodeJS space but pales in comparison to Django's ORM. At least for now.

Relationships must be done manually, including joins, traversing, and many to many.

Sometimes doing:

w = Widget.objects.get(pk=2) w.category.author.name

Is just all you need. And Django makes that trivial.


This. Yes the site won't be as fast, and yes you don't have realtime.

But if you need a regular web site, not a real time app with 100000 users, then nothing BEAT those techs.

They are mature, stable, productive, and incredibly flexible.

If you use anything else and you need something that is not "the typical hello world", you will have to write it by hand. With DRF ? You google it, you find a module and call it a day.


I'm on the same boat. Django or Rails are so much more productive for me that I feel that most of the Node.JS love for this sort of domain comes from people who have never tried anything better.


The operative words here being "for me".


It sounds like you are describing C# with Entity Framework. Throw in the self-hosted OWIN webserver and WebApi or Nancy and you're good to go.

I'm not really up on the state of DotNet Core or whatever they are calling it this week, but when that is shaken out, I'll be interested so see what kind of inroads it makes on Java and Python in the Unixy server world.


JavaScript is a scripting language. So is Python and Ruby. As a scripting language, excluding all bindings (files, networking, etc), JavaScript is substantially faster than Ruby or Python.

Now, in terms of bindings, bindings to libuv are also fast. So node is not so much of a problem in itself.

However the problem is how the language is being used:

To say you can write a serious library or server code because you know JavaScript, is the same as saying you can write a paper in cardiology research because you know English.

You will find a lot of people that completely disregard the domain knowledge required to write safe, workable code. While this happens in many languages, JavaScript is the lingua franca for those kind of people.

Because of this, be very careful of the libraries you use. You will most likely have to read the code to ensure there is some thought behind it.

Then if you are hiring node developers, prepare to receive an avalanche of resumes from people without a degree expecting to learn on the job at your expense while receiving a 6 figure salary.


> As a scripting language, excluding all bindings (files, networking, etc), JavaScript is substantially faster than Ruby or Python.

This makes no sense.

They're all dynamically typed languages (avoiding the term "scripting languages" since it's pretty vague).

The only reason for the difference in speeds between these languages is due to the quality of their interpreters, not the languages themselves.


> The only reason for the difference in speeds between these languages is due to the quality of their interpreters, not the languages themselves.

That's not entirely true; there've been fairly good write-ups on particular elements of language semantics for which support inhibits VM performance; for instance, there were particularly good write-ups a while back by the JRuby team (Charles Nutter, specifically, IIRC) on Ruby semantics that are problematic in that respect.

Obviously, that doesn't mean that the level of investment by major firms in the interpreters doesn't have an impact, and Node is definitely riding high on Google's investment in making V8 speedy for Chrome. But language differences do matter.


Yeah, since PyPy is V8 fast, LuaJit is faster, and Julia is even faster.


I'm not a PL expert, but Ruby's semantics seem much more complicated than JavaScript's.


Perhaps, but Ruby is are more consistent. There is no implicit conversion, no optional semicolons, no dynamic this, the inheritance chain is not disguised by Java-like syntax, everything is an object (there are no primitives), object construction is always uses the .new method, containers mixin Enumerate for a consistent API across arras, hashes, etc. There's no need for "use strict" or built-in statements like with to ignore. All operations are messages between objects. You can extend the semantics by defining message operation on an object, so that you can use + for more than the builtin classes, where it makes sense to do so.


If you have embedded or extended a scripting language it makes perfect sense.

Repeating myself just for you: I was referring specifically to benchmarking language aspects excluding bindings to native code such as files, networking, processes, etc.

e.g: https://benchmarksgame.alioth.debian.org/u64q/compare.php?la...

Then sure, JavaScript has many implementations, so does Ruby and Python. I was referring to v8 (used by node), CPython and Ruby MRI in particular.


I think a lot of that is baloney. Not all apps require the same degree of rigor. In fact most require quite little. If a library is widely used, that's a pretty good indication it's "safe".


What you describe is a functional prototype not a finished application.

A functional prototype is software that implements its functional requirements (e.g: features) but not its non-functional requirements (maintainability, stability, scalability, performance, configuration, monitoring, security, etc.)

What is "a lot of baloney" is people selling functional prototypes for the price of a finished application, or not knowing the difference.


Tror inte det blir brunch på stan på söndag


At a previous gig, without getting into specifics, we built a huge internal client-server system. The client was written in Node.js and ran as services on both Windows and Linux on a few thousand machines. The server was written in Node.js and ran as a Linux daemon.

Node.js matched the developers' skill sets and gave us the ability to quickly write a server that could easily handle several thousand concurrent requests from the clients. On the client-side, Node.js gave us cross-platform support for nearly free (as well as being within our skill sets).

Looking back, I do not think the project would have gotten off the ground in any other platform in that specific organizational environment. The server on Linux was particularly well-suited as it was architected to scale horizontally but still had room to scale vertically.

On the client side, while we were able to get the Node.js service out pretty quickly, it eventually had performance and integration issues, particularly on Windows. It was super frustrating having to shell out to external processes or write native C++ modules to get access to some needed Windows APIs. In hindsight, I would have tried to rewrite the Windows client sooner in C++ or C#. On the plus side, it was a huge advantage that the entire Node runtime fit in a single executable (no dependencies on a huge JRE or other runtime).

Overall, I would recommend it as an option to consider if most of the following is true:

* Need to get to market quickly * Application is I/O intensive rather than CPU intensive * Dev team already knows JavaScript * Target environment is not Windows

Personally, I decided to move away from Node.js and these days if I was faced with the same problem I would lean toward a JVM language or Elixir.


> * Target environment is not Windows

That one is still my main problem. I know, I know, Windows is evil and so on, but our customers use it. We are remarkably free in choosing our tools or whatever, but Windows is usually a constant (Intranet environments) and every day I crash against the absolute "Windows is a second class platform" problem of NPM modules. For an environment which is supposedly platform-agnostic the amount of "only on Unix" is astonishing.


Really? I think exactly the opposite. Compared to a lot of other tech, I found nodejs to work pretty well on windows. For example, recently npm switched from a nested to a flat directory organisation in node_modules. Windows has a limit on the number of nested directories, so this new organisation helped a lot.

Maybe that you use a lot of modules with c dependencies?


So I felt this way until about...oh...a month ago. Because my JavaScript experience was mostly ES5. And ES5 is a roiling piece of shit that I wouldn't wish on my worst enemy. ES6, however? ES6 is tolerable. Getting it set up isn't as bad as you'd think and the language does as much as a Ruby or a Python in not shooting yourself in the foot. I'd trade async/await for actual threads, because I am capable of writing code with threads without hurting myself, but async/await are fine for get-it-out-the-door web services and that kind of thing. So I don't worry about it that much.

I'd still go reach for the JVM and languages like Java or Kotlin if I was going to be hammering on a piece of code on an everyday basis for two or three years. But in 2017 (and probably 2016, but 2017 was when I got to it), it just became good enough to get it out the door with.

(Regarding TypeScript: I feel like it's an incomplete thing and I'm happy that it exists, but for the stuff I use ES6 for I can hold the entirety of it in my head and I'm not worried about typing. For things that matter to me...well, I wouldn't be using ES6 in the first place.)


Sadly, I've been going through a similar experience after several commenters indicated that my complaints seemed to refer to "old" JavaScript and encouraged me to try ES6.

Between ES6 fixing [0] many of the day-to-day warts that made JavaScript a joke language barely suitable for scripting DOM elements and V8's complete obliteration of other dynamic VMs in speed, I am being forced to accept that JavaScript is maturing into a serious platform, and starting to gradually introduce Node.js into my workflow.

Just today I was discussing how hard it is to pull the stick out of my butt regarding JavaScript, but I think that the evidence is in favor of it. I'm having a strong impulse to try to use Dart instead just so I don't feel as dirty anymore.

[0] http://es6-features.org


NodeJS has a handful of things that tend to get brought up. Callback soup and difficult error handling. Both are resolved by promises. Once you get the hang of promises, you are capable of doing concurrent asynchronous tasks in a manner that would be significantly more difficult in any other language.

On top of that, NodeJS is very, very fast. Compared to Python or Ruby, straight computing is significantly faster, but that's not even where the meaningful gains come from. Because NodeJS is non-blocking, the core is IMMEDIATELY available to serve the next request once an asynchronous call is made (read from DB/Cache/HTTP call). Because of this, each core can serve thousands of simultaneous connections.

Because JS is single threaded, in order to take advantage of multi core hardware, you just run the cluster module to effectively launch a concurrent instance of your application for each core.

As far as the language itself, once I understood it, I loved it. At first, I thought it was terrible, but when I went to ES6 syntax, and fully groked how to write asynchronous code, it rocketed to my favorite language.

I started with Java, moved to Python, and although it took me a while to come around to JS, I would absolutely never go back.


> Once you get the hang of promises, you are capable of doing concurrent asynchronous tasks in a manner that would be significantly more difficult in any other language.

FYI, anyone who has worked with Elixir or Erlang views these sort of statements about Node as completely ridiculous. The only languages right now that are making a serious effort to bring real concurrency to modern programming are Go and Elixir. Node with its single threadedness and global heap doesn't come close, since those are fundamental problems with JS. The papering over the defienct language concepts with attempts like promises don't address these issues at all.


For concurrent asynchronous tasks, being single threaded or multithreaded shouldn't make any meaningful difference. To make a million concurrent asynchronous calls on a single thread takes couple MS, to make on multiple threads takes about the same. For concurrent SYNCHRONOUS tasks, being single threaded or multithreaded makes a huge difference, but that's not what we're talking about here. It's also not at all fair to call NodeJS single-threaded in regards to its concurrency model, as it utilizes all cores through parallel application instances.


The multiprocess Node concurrency model is brittle and fault intolerant. The event loop scan actually has real bottlenecks at a certain level of fds in flight. A real scheduler really wins here; libuv sits below the knowledge of the runtime to really be optimal. You become CPU bound far sooner than you expect.

With a global heap, you also become memory bound far sooner than you expect as well.


Your typical Node instance is using an order of magnitude less memory than the beastly JVM. We use Java microservices with Spring at my job and each "micro" service consumes close to 1GB of memory. I've never written a Node service that had more than 100MB footprint.


The default maximum heap size for the JVM on systems with 4GB or more of RAM is one gigabyte. Has this been changed in your microservices' startup parameters? If not, it is no surprise that Java uses the memory that you have allocated to it before garbage collecting.

Spring Boot microservices that don't do much shouldn't need more than 32MB heap -- see https://spring.io/blog/2015/12/10/spring-boot-memory-perform... for details.


The JVM has the same global heap problem as Node... it's frustrating that with all the development that goes into the JVM this problem remains unaddressed.


When they say node has great ease of asynchronous non blocking IO, they are certainly not talking about vs golang or erlang. As much as the concurrency is fake, as long as _real concurrency_ is not a fundamental business requirement, it's way better than literally no concurrency.


Julia's support for concurrency is right there with Go and Elixir.


Will take a look! There really should be more ecosystems that try to solve modern problems effectively.


> Once you get the hang of promises, you are capable of doing concurrent asynchronous tasks in a manner that would be significantly more difficult in any other language.

Of the top of my head, concurrent asynchronous tasks are simpler in Pony, Go, Erlang, Elixir, Haskell, and Oz than in JS (and these generally also handle parallelism beyond "run another instance of your app", too); and lots of other languages have concurrency constructs equivalent to JS promises (and, often, also async/await), so JS is at best no easier than that larger group.


> you are capable of doing concurrent asynchronous tasks in a manner that would be significantly more difficult in any other language.

"any other language" is a bold claim. I heard Haskell gets concurrency more elegantly, or Erlang.


> Once you get the hang of promises, you are capable of doing concurrent asynchronous tasks in a manner that would be significantly more difficult in any other language.

What languages are you comparing against? It seems like asynchronous code is more difficult to write in NodeJS than in C#, Go, or Rust, and about the same as Java. I can write code in Java in a style similar to promises using ListenableFuture (Google Guava) or CompletableFuture (Java 8) [0].

I should also clarify that I don't think promises are the optimal approach to asynchronous code. I think you can do better, and the primitive "await" is an example of how. Bob Nystrom (munificient) wrote an article called "What Color is your Function?" [1] that does a good job describing the difficulties of promised-based async, and how await improves on it, and how Go does even better.

(From what I've read, JavaScript ES8 is supposed to include async/await, and NodeJS seems to have support for them. At that point you'll be able to program in standard JavaScript and use await, which will bring NodeJS up to parity with the first-tier languages.)

> On top of that, NodeJS is very, very fast. Compared to Python or Ruby,

Perhaps that's true compared to Python and Ruby, but not when compared to other high-performance runtimes like Java. The following three paragraphs are from a comment I previously wrote on this topic [2].

Folks might also be interested in the TechEmpower web framework benchmark [3]. The top Java entry ("rapidoid") is #2 on the benchmark and achieves 99.9% of the performance of the #1 entry (ulib in C++). These frameworks both achieve about 6.9 million requests per second. The top Java Netty server (widely deployed async/NIO server) is about 50% of that, while the Java Jetty server, which is regular synchronous socket code, clocks in at 10% of the best or 710,000 R/s.

NodeJS manages 320,000 R/s which is 4.6% of the best. In other words, performance-focused async Java achieves 20x, regular asynchronous Java achieves 10x, and boring old synchronous Jetty is still 2x better than NodeJS throughput. NodeJS does a pretty good job given that it's interpreted/JITed while Java is compiled, though Lua with an Nginx frontend can manage about 4x more. NodeJS is handicapped by having to orchestrate everything from its single thread.

I agree that asynchronous execution can provide an advantage, but it's not the only factor to consider while evaluating performance. If throughput is someone's goal, then NodeJS is not the best platform due to its concurrency and interpreter handicap. If you value performance then you'll chose another platform that offers magnitude better requests-per-second throughput, such as C++, Java, Rust, or Go according to [3] and [4]. But I'll grant it has better IO performance than many other dynamically typed languages.

Asynchronous execution also does not necessarily require explicit async programming. Other languages have as good or better async support -- for example, see C#'s `await` keyword. [1] explores async in JavaScript, await in C#, as well as Go, and makes the case that Go handles async most elegantly of those options. Java has Quasar, which allows you to write regular code that runs as fibers [5]. The code is completely normal blocking code, but the Quasar runtime handles running it asynchronously with high concurrency and M:N threading (similar to Go). Plus these fibers can interoperate with regular threads. Pretty gnarly stuff (but requires bytecode tampering). If async is your preference over Quasar's sync, then Akka might be up your alley instead [6].

Lastly, high performance servers don't necessarily require asynchronous code at the application layer; performance sensitive logic can often live in the library or framework e.g. Netty, reverse proxy e.g. Nginx, or in the OS's context switching.

> Because NodeJS is non-blocking, the core is IMMEDIATELY available to serve the next request once an asynchronous call is made (read from DB/Cache/HTTP call). Because of this, each core can serve thousands of simultaneous connections.

This also describes regular synchronous code with many threads. Once your application makes a blocking call, the operating system context switches to another thread (process). This is how boring old blocking Java code running on Jetty outperforms NodeJS in request-per-second benchmarks [3]. And you could take advantage of this in NodeJS too if it weren't for the fact that JavaScript execution occurs in a single thread!

For most typical applications, overall performance is more influenced by the efficiency of the runtime than it is by the concurrency/async strategy.

[0] https://github.com/google/guava/wiki/ListenableFutureExplain... and https://docs.oracle.com/javase/8/docs/api/java/util/concurre...

[1] http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...

[2] https://news.ycombinator.com/item?id=12341886

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

[4] https://news.ycombinator.com/item?id=12268988

[5] http://docs.paralleluniverse.co/quasar/

[6] http://akka.io/


that's a lot of text you wrote for something that will get automatically disregarded by anyone with a brain for having mentioned plaintext response benchmarks


what would be wrong with that?

secondly, what do non-plain-text benchmarks give us?


Love this. This is precisely why I love Javascript too, I find these douchey condescending comments on Javascript/Node.js from people who've not grasped the language and it's philosophy deeply, extremely annoying.

There's a lot a capable developer can accomplish with Javascript, with it's first order functions, collection operations, generators, promises and now, async /await. Granted JS is not idiot-proof, but I'd any day use a powerful language than a highly restricting one (think Java and Go).


Or maybe they just don't share the philosophy. Or are opposed to it. A lot of Node enthusiasts also come across as douchey and condescending as they claim that people just haven't grasped the language or its philosophy.

I think Node is absolutely fine. But I see why someone who values robustness and error-reduction as primary goals or someone that has a firm grasp on other asynchronous models might not see many advantages to Node. Just as some people value stability higher than progress, neither is necessarily evil, just beliefs.

People have different priorities and Node delivers on some and is not geared towards others.

But I don't find Nodes async, single thread model very interesting or revolutionary. It is very pragmatic and definitely useful but I found the Erlang VM and Elixir a much more compelling solution for example.


Hey, more power to you if you want to use more expressive/functional languages than Javascript like Erlang or Clojure. However claiming that a language that allows nothing beyond the Object oriented model of computation like Java or Go is more robust or allows you to have less errors would not be accurate (see the comments above).

The primary reason anyone would use Javscript over say Erlang would be the ubiquity of the language and the availability of libraries or strong familiarity with the language. But my point is Javascript provides you the tools to write functional code that is robust (if you are disciplined) and generators + promises (and async/await) makes the single threaded async model painless. I certainly did not claim that it was a silver bullet or a revolutionary model of computation.


> Once you get the hang of promises,

.then( you realize it's just a callback..


What language doesn't have promises these days?


From some JavaScript training slides I am working on:

Why use it:

    - Server and client side in the same language
    - Simple enough for you to feel free
    - Enough hammers not to forge your own every time
    - Fast enough
    - Good enough to structure larger programs
    - Browser is the only cross-platform GUI toolkit
When to use it:

    - Web applications
    - Network clients and servers
When not to use it:

    - Computation (CPU) heavy programs
    - Very high loads
    - Shell scripting
    - Raw packet requirement


For me the question isn't so much why do I choose Node.js and Javascript over other languages, it's why do I choose NPM over other module libraries. I think the ergonomics of the libraries and command line tools we use have a much bigger impact on our coding experience than the language itself.

And what I like about NPM is that there are a LOT of single file modules with a narrow, well defined scope. There are exceptions to this, like Ember or Angular, where they try to package up everything you might need. But there are also smaller frameworks like Vue.js and even smaller packages still, which do a single aspect of data binding or rendering or whatever.

And it's those granular little packages where I think the NPM community ends up exploring just about every possible way to do get something done, and often comes up with a new idea that can teach me something.

The organizational and software complexity behind an interface like Rails or iOS or Ember I think discourages app developers from questioning the interfaces they are using, and participating in shaping the landscape under them. I think that's a shame. The NPM community does it better.


I've used nodeJS at 3 of the past 4 startups I've worked at (currently using PHP). I had a hand in choosing it at all those 3 places and my main reasons boiled down to:

1. most devs know JS (so it's easier to hire & onboard new devs)

2. while everyone claims node's dependencies are hell, I love the choice available (although over time, it's tiring).

3. The community is generally awesome (helps during meetings, online etc.)

4. Developer Exp: With TS, Tslint etc, devx is not too bad IMO (and there's no dearth of opinionated articles around on the correct way to do things)

5. Finally - we can quickly churn out prototypes for features to production (but I guess that's more experience than the tools?).

6. In general, we'd be using JS on the frontend anyway (React), so it just made sense to use one language everywhere.

7. In general, most tools have JS SDKs and JS language support is always around (an exception I found was Tensorflow) - as an example, AWS Lambda supports Java, Python and JS.


I'm pretty much a beginner developer, doing a few small things but not employed as a dev. I like JavaScript, and when I wanted to do server side stuff (like automate schedule emails at my company), solutions were really available in PHP and it worked right away on my local machine with mamp and on my super cheap web hosting, whereas I seem to hit various setup pains when I try to do something with node. The PHP syntax was close enough for me to be much more comfortable than I expected to be. I recently worked on something that logs a user in to a mobile-unfriendly website, scrapes and parses a specific page that you would want to see on mobile, and presents a nice mobile view, with some extra relevant information. All the scraping is done in PHP and it just returns json that gets displayed with a handlebars template. It's just a demo right now, but my point is that even knowing a bit about JS, PHP feels so much more accessible than node for me, and I've done stuff that a year ago I never would have thought I could do. I feel like solutions are close and only require language and library research. Node solutions also require this other layer of knowledge that I haven't clicked with. How is PHP treating you at your current job?


> while everyone claims node's dependencies are hell, I love the choice available (although over time, it's tiring).

So... at one place I work, we use nodejs. There are so many modules added using so many files, that we ended up not being able to use our packaged application - extracting the package into a holding dir before moving into place meant that we ran out of inodes on the filesystem (stock 8GB ubuntu ext4 cloud image)! The filesystem could not hold two copies of our app, basically, due to inode exhaustion. The easy workaround was "increase the size of the disk", which seems silly given it's 80% free space.

This has apparently been fixed in recent times with flatter npm structures, but watching the nodejs community run into every single packaging roadblock that has been solved before is just disheartening.


> watching the nodejs community run into every single packaging roadblock that has been solved before is just disheartening.

Deeply nesting packages was specifically designed to fix the issue that other packaging systems have: two dependencies needing different versions of a third dependency.

Flat-where-possible structures (ie, npm v3 and up) were designed to improve this. They're excellent and npm is the only place I've seen them.


I had this issue initially when I was developing on Windows. We hit the limit of Windows's 255 char file path limit.

We also have had issues with node_modules takes minutes to download to the point that we basically had to cache it in our CI builds - which in itself was a really bad idea (thankfully Yarn seems to fix a lot of those issues)


Seriously. NPM/bower downloads are at least 50% of our CI build time - which also includes compiling a largish C# solution, running unit tests, generating PDF documentation, building an installer, and putting everything through ReSharper code inspections.

That's when those download/install steps don't just fail for some unrecorded reason.


Seriously, Node has been the worst platform when it comes to managing its ridiculous (in a bad way) ecosystem of packages where there's no standardized solution for anything.


There are a lot of negatives, but it is any easy language to make rapid progress writing code in, and ES6 or TypeScript have made it a lot better than it used to be. You can do a lot of prototyping in the browser REPL too (e.g. I like to go to the lodash docs, write out code on the site, then paste into my app).

It's nice to be able to do server side rendering (i.e. run React there). Also you can run all the build tools in your application server during development which can be super convenient - Probably the most compelling example I've seen of this is Next.js.


You're not wrong.

InterSystems Caché is easily the worst tool I've ever used. A typo in your code often caused the compiler to bork your entire runtime. Not kidding.

Node is almost that bad. Stately as nicely as possible: it's syntactic vinegar for a type hostile flow of control obfuscation framework.

If you have some irrational need to use libuv (callback hell vs actors, CSP, multithreaded NIO, or AIO thread per connection), you're much better off just using 'C'.


A bit flame-baity but I liked your point for the description. Syntactic vinegar was new to me and type hostile felt novel.

Also a good example of how it needs to be okay that some people just don't like Node. While also illistrating that they could also, arguably, be nicer about it ;)

What area do you generally work in? That often influences the view of which tools are suitable.


Being able to run the same code on the client and server is a boon for web sites - rendering views server side then hooking up client events is a lot more performant than only rendering on the client side.

Also, context switching - the projects I work on tend to be front-end heavy, with a little API access and data storage on the backend. I find it a lot easier to do that backend work with the same language, tools and debugging environment as my client code.


I'm a huge proponent of using the same language in front and back end. My best teams had C++ front & back, or C# front and back, even Java front and back. Even though one language/platform isn't ideal for both ends, the benefit of getting everyone on the same tools, libraries, processes and way of thinking is invaluable.

So these days where most front ends are JS, it makes a lot of sense to have a JS back end too.


I've been using NodeJs for about 4 years now. It really lends itself to the microservice paradigm. It makes great networking glue as you can handle many simultaneous connections without using many resources and since most web server operations are just fetching/updating data between databases or other services this works out well in NodeJs. The trick is to use it for this purpose only. Long running computations should be offloaded to the database or workers running in another process or machine.

A lot of the problems mentioned in that article are the author misunderstanding libraries and not actual issues with NodeJs itself. For instance the problem with the Postgres library was that he didn't read the docs. The lib uses a session pool by default. You have to release the session when your done or else it will not become available again until the default session timeout is passed, which is quite large in Postgres. In respect to using Coffeescript "Classes", forcing JS to work like other languages will create unexpected behavior. It uses prototypical inheritance, not class inheritance.


Node.js being based on JavaScript was accidental I believe. What the developer was after was an asynchronous, evented, non-blocking/non-multithreaded server runtime for game servers and similar apps without Java et al.'s "synchronized" and "volatile" model.

Of course, Node.js is only suited for I/O-scheduled but not CPU-heavy workloads.


I can say why I chose it and why I no longer choose it anymore. For me, JavaScript was the price I had to pay for a number of other benefits. I don't like the language, but TypeScript, Coffeescript and the like can paper over some of the deficiencies well enough. But what Node is is more than just JavaScript.

It's a fast, well-designed runtime written in C++ with the event loop as a central construct. It's an ecosystem where async is the default and you don't have to work hard to get performance and scalability in that area. And it has a fantastic package management tool. The quality of the packages that npm installs may not always be high, but the tool itself is so much better than pip, maven/gradle, gem, cpan, etc.

I've moved on from Node because I've found nearly all the benefits of Node available in Rust. Rust has the performance of Node's C++ runtime, easy event loop with tokio, and cargo is the one package manager that I think betters npm. And with wasm, we're even starting to see the possibility of sharing code between the server-side and client-side. Add to that the ability to use it anywhere that Node can be used (I'm using Rust now with Lambda without a single line of JavaScript), and there's now no reason for me to put up with the hassles that using such a poorly-designed language as JavaScript imposes.


My reasoning: all of the dynamically-typed languages are more or less the same on the server for CRUD apps, so I might as well use Javascript.


I find there are really big differences between the dev experience in Python, Node, Clojure and Erlang. JS doesn't trap errors[1], so it's tedious to debug or to have confidence in correctness, and the callback hell APIs are high friction in interactive/REPL development. Node is a fine vessel for running ClojureScript though ;)

[1] See eg the bit about NaNs in the article.


I agree that Node once felt tangibly worse. I used Clojure for three years to avoid Node until I had to use Node at work (nobody was going to learn Clojure) and I discovered Koa when it just released.

Even back in Koa 1, co/yield/function* closed the gap for me. Nowadays it's much better with ubiquitous promise usage and async/await.

I miss various things about Clojure like the editor-as-a-repl development cycle, but in my opinion, they still amount to small technical differences that play second fiddle to business concerns.


It's interesting that JavaScript on the server has grown at the same time front & back ends have separated. Which in my experience has drastically reduced development speed.


Hmmm, that hasn't been my experience: http://www.phoenixframework.org/


I haven't used it, but it's still the same pseudocode:

    defmodule HelloPhoenix.UserController do
      def index(conn, _params) do
        users = HelloPhoenix.Repo.all(HelloPhoenixUser)
        render conn, "index.json", users: users
      end
    end
For CRUD, I'm not too convinced it's much different than what you'd be doing anywhere else.

For websockets, streaming, and other stuff beyond request -> database query -> response, then competing abstractions get more interesting.


So I'm curious as to the reasons people chose Node.js

Javascript of course ;)

You can leverage the same language for server side stuff and browser programming.


But how valuable is that? I hear this a lot but is it really that much of an inconvenience to write backend code in a different language? Especially if there are different engineers working on the frontend and backend.


It's very valuable if you are bouncing back and forth between frontend and backend. There's no context switching as you do that. The cognitive overhead of context switching is higher than people generally accept. This is why stacks like the MEAN/MERN stack get used in hackathons. You've got a JSON-inspired database (Mongo) with a minimal server-side framework (Express) feeding a React/Angular front-end. You can use the same libraries client/server side like Mocha for unit testing, Lodash for collection manipulations, you can even share the same validation files for server & client.


"There's no context switching as you do that"

So, you just read/write to a database wherever? Or do you have to remember the context the code is running in?

There may not be syntax switching, but I think you stil usually need to remember where the code in question will be executing (well... I need to, anyway)


Language is never the problem. Languages (mostly) are easy. Frameworks are hard. Tooling can be hard (pick a language).

Javascript is easy. Express, NPM, Bower, <insert framework of the month> are tough.


I've never run a javascript server in production, but if I do the main reason would be to take advantage of the huge ecosystem. Since js works on both the client and server side, you end up with a lot more programmers hacking on it.

If you check http://www.modulecounts.com/ you can see that npm has as many modules as all the other package repos combined. And it only seems to be gaining momentum. (screenshot: http://imgur.com/a/adqNJ)

Meteor has more stars on GitHub than any other web framework: https://github.com/search?p=3&q=stars%3A%3E1&s=stars&type=Re... Nodejs, socket.io, and express all appear on the first few pages.


If you are using a web framework, and are considering switching to a systems language, and your developers already have a lot of experience in JavaScript, that's when you should consider NodeJS! I had a lot of JavaScript experience before switching to NodeJS, but it still was a huge step, you have to learn systems architecture, and distributed systems (async programming). I think JavaScript is easier then Java and C/C++, but it's still hard to learn, having the same language for both front-end and back-end makes up for that though.


I have a hard time really seeing this as a net win. There are huge upsides to having the same language on both sides - but the big downside is that javascript simply isn't a very good backend language. Node.js/v8 is incredibly impressive for what it is. But it still has "shoehorned" written all over it. (For the record: I wouldn't consider Java the Language a pinnacle either.)


I agree that JavaScript isn't very good, but what are the alternatives !? I can not think of any language where a non-engineer with little computer science knowledge, can get productive withing minutes. And it only gets better the more you use it. For example, the other day I wanted to take a screen-shot of a web page, make a visual diff, then email me if something changed with the changes highlighted. I basically glued three different NodeJS modules together, and it took less then a hour. Try to do that in any other language.


> I can not think of any language where a non-engineer with little computer science knowledge, can get productive withing minutes.

That's a big misconception there. I absolutely don't mean this in an elitist way - and I completely agree that some degree of accessibility is a must - but this is in no way a benchmark for a good backend language. This is how we got PHP.

> [WebPage screenshot -> visual Diff -> send mail] > Try to do that in any other language.

I fail to see what's so difficult about this. I'd wager that in the "heavyweight stacks" you'd not even have to use modules outside the runtime libraries for a basic variant, and if you want to, you'd have them at your disposal.

Don't get me wrong, the large centralized ecosystem of NodeJS definitely is one of its biggest pluses.

But - and yeah, now I'm sounding a bit elitist and jaded - I've heard a variant of "It's so much simpler in X" or "Try that in anything else than X" too often when it only meant "I'm actually not really proficient in anything else but X".


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.


> 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)


>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.


> 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.


So I'm curious as to the reasons people chose Node.js

For work that is almost entirely IO bound Node is really fast and easy with asyc concurrency that works really well. Compared to most other solutions out there will you get a very fast solution very quickly. For problems which basically reduce to

  -Wait for GET/POST request 
  -query a bunch of databases based on request
  -return result of DB queries as JSON
Node works really well.


I do not like javascript. I am using it on my server because of performances. It has about the same execution speed as java, a slightly smaller memory footprint, but with the async io, it ensures best use of cpu with none of the hassles of multithreads. No need of apache or nginx, with a single process, you can serve hundreds of simultaneous users with blazing performances


There are quite a few Netty-based web frameworks faster than Node.js


If you want to run the same code on the browser as on the client (for example in a scheme where you want to reduce latency by optimistically running server-code on the browser), it is nice to have Javascript on the server.

But you could also achieve this by transpiling another language to Javascript of course.


Check out Typescript!


I actually have, but it doesn't alleviate my biggest issue with Javascript, which is its async story.

Also I've had experiences with Typescript code compiling with an error then immediately recompiling without any errors. Then errors when I switch to my browser. The immediate recompilation is probably just webpack but it doesn't inspire confidence when errors are non-deterministic.


Typescript plus async/await is a beautiful solution to both the async story and typing story.


I don't think asnyc/await is a good solution to asynchronous programming. Lua, Go et al are more what I was thinking of as good examples of asynchronous programming. See http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...

And I addressed some concerns with Typescript in a sibling comment. It is much better than plain Javascript, though.


async/await is still based on promises, and promises are a naive/simplistic answer to the problem.

It works fine for simple cases, but those are cases that were simple to begin with (Ok, maybe they would not be fine with CPS, but async/await is just thin sugar over promises).

To really solve the async problem, you need either Observables or monadic constructs. The former is much more mainstream and mature in the JS world right now. It's not as cute as async/await and you'll be typing more functions, but it really solves the problem altogether.


The problem I experienced with async/await and Typescript was always the lack of built-in support for promises among the libraries I was using. Once I had to use something like promisifyAll() I lost any type information I had about the library in question.

Is there any better workaround to that these days?


This is changing pretty steadily. For example, the AWS SDK has TypeScript types packaged now and a promise interface. Compare this the boto3, the Python SDK, which has had a story open for years(?) to add async support with no official solution.

Node.js's own libraries are a mix of events and callbacks. Some of it can been "promisified", however they have yet to start a real async conversion AFAIK. I've had to wrap some of this stuff to create async interfaces for my own code.


Not really but I also don't see it as that much of a problem. The libraries I use either provide a Promise based interface or I've written my own as a thin veneer atop a callback interface.

Ditto for apply your own types atop the results. Most are already there and only a few edge cases need to be added.


I had a somewhat different experience. Most of the libraries I used lacked types in the library itself. There were types provided by DefinitelyTyped, but they were often incomplete or out of date, and I think a wrong type definition can be worse than none at all.

As far as writing your own types on top of those libraries, how do you ensure any amount of correctness?

Am I missing something important here?


Biggest benefit, as a solo developer, is one language for everything. I can rip through the front end, and back end work for all my new venture projects, without changing gears.


I mean, you only need one language for front end and back end now, so that can be seen as a win! However, I for one prefer strongly typed languages as much as possible.


> but considering its popularity I'm wondering if I'm wrong

I think places like HN are probably distorting your view of how popular it is.


I don't know. It's definitely not displacing huge amounts of performance-critical Java or .NET yet, but it seems to be gaining inroads in the Real World from where I sit.

I think your average corporate developer is just trying to earn a paycheck and also has a petrified fear of meaningfully learning/using more than one language. Telling him "use this and you can use JavaScript everywhere!" sounds like a big difficulty improvement to him, especially since JavaScript is something he "already knows" and has been familiarized through years of being the exclusive client-side development platform.

Since this type of dev cares only about keeping his career on cruise control until retirement, Node.js is engaged with enthusiasm. In fact, it's one of the most enthusiastic receptions by BigCo devs that I've seen.


In one word: npm

In one sentence: You can build anything with NPM + copy paste in very little time.


To use words from Yaron Minsky, JS is no OCaml but it has a surprisingly decent "dynamic range", even though it doesn't look like it. (Yes, I'm pretty sure I'll end up being ridiculed for writing that, but... hear me out)

Its easy to quickly put up a prototype. There are a ton of libraries for everything, and most come with copy-pasteable examples. Yes, this is frowned upon, and with good reason - but for prototyping, its exactly what you want. The prototype you write will also work much better than your average dynamic language prototypes (except for Erlang).

With generators and async/await the code became fairly pedestrian and un-convoluted. The only additional element in the mix are the few await/yield keywords sprinkled around.

The language is flexible enough that you can also write code in FP style (higher order functions, combinators, etc). For example, RxJS code looks pretty natural.

ES6 and above has all the modern bells and whistles: decent module system, classes, short lambda syntax, template strings... As a result code is pretty much as pleasant to write as Ruby or Python

When your project grows large enough, you have the option to painlessly convert to TypeScript. Besides getting rid of one annoying JS flaw (implicit conversions), this will also improve development tooling tremendously. TypeScript again has a wide dynamic range: you can start out with a fairly lax type system that allows a lot and then turn the dial up by turning on more and more checks (no any types inferred, strict null checks, etc) TypeScript's type system is surprisingly powerful: generics, unions, intersections, type guards, discriminated unions, control flow analysis with exhaustiveness checks, string/integer literal types, "mapped types" - the list is quite large and growing: https://www.typescriptlang.org/docs/handbook/advanced-types.... . But what makes TS different is that it models and formalises idiomatic JavaScript well, so your existing code will not need to be adapted.

TypeScript is where client/server code sharing starts to shine. Shared types enable end-to-end type-checking. You can arrange your code in such a way that data fetching is injectable, and use the same code with fetch on the client and direct method calls on the server (thanks to the same interface). If you have a very demanding client-side app, there will definitely be a lot of code reuse opportunities. (Nowadays I suppose this is also possible with Scala.js and bucklescript)

The lack of threads is a mixed bag. Most people already covered the disadvantages very well so I'll mention some advantages. Its much easier to reason about stateful code, since you can treat each synchronous code chunk as uninterruptible, and the possible interleaving points are always obvious (e.g. await/yield keyword). There are also several techniques and libraries to work around the disadvantages (e.g. dnode for RPC to separate processes for intensive calculations) and while none of them are very convenient, they usually end up being what you have to do eventually anyway. Threads will only get you so far with servers running CPU intensive jobs - soon you will need more than one machine and then you can't take advantage of shared memory any longer.

If all else fails, you can probably throw more processes at it and put a load balancer. Thats an interesting project, and AFAIK not yet solved (at least not in the node ecosystem). You would need a load balancer that is aware of the current state of the node processes - round-robin or random algorithms will be far from optimal to be helpful. I started some work on this here: https://github.com/spion/least-latency-balancer but I'm sure that its not the best approach and that it can be improved a lot. Might be a good idea to look at what the OCaml folks have - I'm pretty sure they've been dealing with a somewhat similar problem due to the lack of multicore.

Another way to attack this problem is to have better monitoring for long CPU-bound tasks e.g. https://www.npmjs.com/package/long-task-detector

But I will admit that in this regard, there are languages/runtimes where the situation is far better: Haskell, Go, Erlang to name a few.


addendum: turns out things are better in OCaml as well since OCaml threads will yield at not only IO but also memory allocation points.


I only know JavaScript (and I know it quite well). Why learn a whole other language, when Node gets the job done just fine?


Learning a new language will make you a better programmer.

Especially one with different paradigms


I’m not sure that being a “better programmer” is important in web development. And I don’t mean that term in the broad sense—obviously, we should write good code—but in the sense that understanding two programming languages makes a significant difference. I think in web development it doesn’t.

Web development is about many things. HTML, CSS, performance, accessibility, security, networking, supporting different browsers, polyfills and workarounds, keeping up with new features, UX and usability. Then there are frameworks and build tools, which are all of course JavaScript-based.

Only a small part of web development is actual programming, and the fact that frameworks most of the time lay out the patterns for you, makes the “programmming” aspect even less significant in the overall picture.

So no, I don’t think that learning another programming language is a good way to spend your time if you’re a web developer.


That makes me wonder, what number of "choose to use JavaScript" is compared to "have no real choice, because JS is the only language they know".


Because nto everyone suffers from Stockholm syndrome?


Reading up on all these Node.JS posts I'm surprised at just how many gotchas the platform has and how there's no single standardized way to solve them.

It's not encouraging stuff. On paper the platform looks decent but aside from a few use cases it seems that there's more hype than it merits.


What really scares me about the Node ecosystem is bugs like these:

https://github.com/npm/npm/issues/10999

https://github.com/npm/npm/issues/9633

I have personally hit both while trying to build (not even write!) Node software.

The former bug is an example of "broken by design", and it's interesting that it remains open (therefore admitting that it is a problem?), but no solution came yet. Although I believe Yarn doesn't have it - but then why doesn't the entire Node community move to Yarn?

The latter bug is, to me, just insane. Several dozen bug reports (and even more if you google for the error message); and when it shows up, it can be an outright blocker. It was for me - I plainly couldn't build the software that I wanted, and no workarounds helped. And no fix, 1.5 years later and counting.


Technically those are NPM bugs, not Node bugs. And Yarn seems to do a much better job these days.


That's why I said "Node ecosystem". NPM is definitely a part of said ecosystem, and it still the de facto standard package manager (which, also - why, when there's Yarn?).


Yeah. I've had production experience with node.

It's been the single least productive coding environment of my life. When you're taking care of large systems of backend servers, Javascript is pretty far down on the list of languages I'd pick to use. Add to that Node's explicit handling of asynchronous operations instead of just blocking and waiting.

Also, it seems to get worse the more code you have. I'm sure it's possible to write really good readable javascript in large codebases, and the same for Node, I just haven't seen it done.

Another subject the author brings up is "the ecosystem". Javascript has so many libraries that keeping up with them, their updates, and using them in a canonical way throughout a large codebase is a full-time job for at least one engineer.


> Another subject the author brings up is "the ecosystem". Javascript has so many libraries that keeping up with them, their updates, and using them in a canonical way throughout a large codebase is a full-time job for at least one engineer.

I love the language, but this is absolutely true.


Same, and same. It's very research-y. It is an incredible place to work if you treat your development process like research anyway, but if you just want to jam through production cycles I would pick Python or something stable.


So, not development?


I would say research-y development: building with the understanding that some percentage of the time you will be building only to learn.

Also, there is a lot of research in design, and I do design and development interleaved. I could carve out slices of that work to call "pure development" or "pure research", but for me, design, engineering, and research are all part of one tightly coupled process. I call that process development for shorthand. Is there a better word?


Use https://Greenkeeper.io to automatically get PRs on dep changes. Coupled with a good testsuite, it's work very nicely. - happy user


> Verify All Assumptions

When you have to worry about the environment unexpectedly reusing internal variables, when is it considered foolish to use a framework where you have to question every relationship between every concept? Just stop using it.


Or one could learn how `this` works, which is that example is really talking about. I was unimpressed by these lessons. There are no dark corners of Node, or JS in general, here. It's more of a narration of the author's growth as an engineer. The "call the callback last" recommendation is particularly odd.


The counterintuitive behavior of "this" in JavaScript doesn't need any defending. I've never heard a justification for this or any other of JavaScript's quirks that wasn't just a thinly veiled lecture on how it works.


They should name it arg0, as that is more indicative of what it is than "this".


if nothing else, the javascript "this" is teaching people alternatives to coding that don't need it in the first place.

(I don't think JS "this" is that bad...it's just not needed at all)


Yeah...I think we have to use some context clues in interpreting this particular piece of advice. Clearly, he's not suggesting you verify all assumptions as it would take millenia to verify literally all the assumptions that one makes when writing a complicated program.

Personally, I interpret it as meaning he believes that the average developer's baseline calibration for how much is to be assumed is too trusting and people should verify more assumptions than they do-- starting with the most dubious ones of course.


'If you wish to make an apple pie from scratch, you must first invent the universe.' - Carl Sagan



This looks like how I used to work with BASIC back in the 80s:

> I finally added extremely verbose logging ... started adding logging ... Verbose logging to the rescue ... I had the right logging in place ... My first step was to jump in and add some key logging statements ... added extremely verbose logging

Weird to see people happy to be limited to such stone-age work-flows when fully capable debuggers have existed for almost all proper languages out there the last 30 years.

Based on this, it's hard not to state that current Node-developer are the new PHP-developers: Unsophisticated, completely unable to see when the tools at hand are lacking, and happy with a with whatever they can get running.


> Based on this, it's hard not to state that current Node-developer are the new PHP-developers: Unsophisticated, completely unable to see when the tools at hand are lacking, and happy with a with whatever they can get running.

Comments like this are not the problem with HN.

The fact that they get voted, literally, to the top, is.


It's not a bad comment, it's just blunt. I also have a similar stories as the parent commentator, 8-10 years ago when you had even more awful programmers I would sometimes agree to fix something for someone desperate as their own coder had disappeared/failed/etc.. Sometimes even in a language I'd never even used. I'd open some random PHP project, or VBScript, or whatever and find loads of commented out print statements surrounded by some godawful code.

And it'd often be quite a simple logic bug that I could see straight away.

Regularly using logging for debugging is often an inexperienced developer's crutch. It's a red flag, the sign of the desperate, that they can't comprehend their own code or don't seem to understand the business logic.

It can be a bad substitute for replicating the problem, reading the code + using a debugger.

Sometimes it really is justified. The author seems to have relied on it a lot though.


>Sometimes it really is justified.

Like in the situations in the article. That's why the comment in question is not just blunt. It's a bad comment.

A good comment would take a specific instance of using logging and said why setting a breakpoint / using a debugger would have solved that particular mystery faster.


I've read the article. Obviously I haven't seen the actual problem, but as an experienced developer, I feel that:

    NaN bug doesn't sound like it needed logging
    Mutability bug doesn't sound like it needed logging
    Dependencies and versions bug doesn't sound like it needed logging
    The Documentation and versions bug doesn't sound like it needed logging
Obviously we're not seeing the whole picture or the whole bug. But that's 4/5. Most of those sound like they needed a simple step-through.

For example, in the documentation and versions async.js bug, he added "extremely verbose" logging where it appears that a simple step-through would have immediately revealed to him the passed arguments were wrong and the signature of the method didn't match the documentation. Which would have made him realize he had the wrong version.

The only one where I would expect to have to use logging is the tests bug.


Interactive debugging is a useful tool, but it can encourage lazy reasoning. People just write something and step through until they notice some change they don't expect. That's fine and everything, but talking about "crutches" and tooling, it sounds like you may be a little biased toward big-IDE style development that makes the debugger the automatic answer v. some reasoning over the code and extra logging of potential trouble spots. There's nothing wrong with logging output v. stepping through in an interactive debugger per se.


Logging is lazy reasoning. Stepping through is simply seeing what is happening with a bug you can replicate. Stepping through is the step in debugging after reading the code.

Even after you've read the code and think you've spotted the problem, you should step through to 100% confirm you've understood the problem.

It's simply confirming the bug and the solution, it's good science, it's good practice. It's empirical.


My comment about the NaN bug: https://news.ycombinator.com/item?id=14156595


I disagree with that assessment. Users reported the order was wrong, he simply had to look at those users and their live data to replicate it.

Even in those scenarios, I rarely have to look at live data, reading the code is often enough to identify it or playing around a little bit. The patience to replicate a bug before trying to fix it.

This is the essence that sets apart a good debugger from a bad one. A bad one resorts to littering the code with print/log statements because either they can't replicate the problem or they simply can't run the code in their head.

I'm being unfair, it's not even that, they simply need more experience. When I was younger I remember complaining that exception stacks were utter gobbledigook, utterly useless. Now, I read one and often know exactly what the bug is. I was completely and utterly wrong, impatient and unwilling to admit my ignorance. At the time I thought I was wise and knowing. They're very useful, I simply didn't understand them.

My "simply" from above belies the years of experience I have.


I have had times when I used logging and then realized I should use a debugger instead.

I have had times when I used a debugger and then realized I was never going to find the problem that way; I needed a larger amount of information that only logging could provide.

I've only been programming about 30 years so I probably haven't hit my peak yet, but my guess is that even with more experience I'll still want to use both tools.

Debug logging doesn't have to be litter either. Instead of commenting out use log levels like with https://www.npmjs.com/package/debug-logger


Do you know why I, personally, agree with this statement to the greatest extent?

Because 17 years ago, I had this same naive development workflow. With PHP, exactly as OP mentioned.

Whenever someone mentions static typing, the canned response from JS developers is "Oh, haha, we actually have unit tests for this" (usually accompanied with a patronizing smile for the obsolete waterfall programmer). Yet when dealing with a real world dynamically typed application from some mediocre company, there are (surprise) no unit tests at all.


Unit tests are a completely inadequate replacement for typing even if they actually do exist, which, as you stated, is pretty rare.

I think the best compromise is optional typing. The language should encourage it by default, but allow some variables to be declared as dynamic/untyped. This greatly simplifies things like parsing of JSON data, which should essentially all be considered a string until there's some reason to consider it something else, but enforces consistency and safety through most of the application. Haxe does a pretty OK job with that.


> I think the best compromise is optional typing. The language should encourage it by default, but allow some variables to be declared as dynamic/untyped.

Like C#'s dynamic keyword (not to be confused with its var keyword, which just does type inference).


Freshness also raises comments higher, not just voting. In time this one will drop.


Frankly, I find your condescending insults to "x-developers" to be a sign of unsophistication, that aside, in my experience, logging is preferable to running a debugger in most situations. Logging gives you an immediate output about the particular state you're concerned with as opposed to using a debugger which slows you down while you fiddle with breakpoints, slowly step through code, hover your mouse over variables and watch values (which are essentially the same thing as logging variables) sometimes with its own side effects (.e.g networking timeouts because of paused execution). Also, logging is mandatory in production because attaching a debugger in production is, at best, a measure of absolute last resort and at worst a fireable offense.

A debugger is a tool like any other, and sometimes it provides unique benefits, like if you're new to a complicated project that lacks appropriate logging and/or you'd like to step through code to try and understand the code's flow, but for tackling individual issues, I would be concerned about non-junior developers who consistently rely on a debugger for solving problems in code.


Are you really implying writing a bunch of print statements is more "professional" than a debugger? Debuggers are incredibly useful in tracking certain things down and don't make you write and then remove a ton of logging statements. Sometimes logging is easier, sometimes debugging is, and not just for "junior devs".


> Are you really implying writing a bunch of print statements is more "professional" than a debugger?

This is quite a loaded question, so let's unpack it a bit.

1. I made no implications regarding anything, my point is explicitly laid out with clear reasoning and examples.

2. I never made any remarks regarding how the use of any particular tool reflects on one's professionalism. I am guessing you're conflating my remark with regard to junior-level experience with the qualities of professionalism, and if that's the case I'll clarify that being junior does not in any way reflect on one's professionalism.

3. Your flippant dismissal of logging as "a bunch of print statements" is unfortunate and broadcasts a blind-spot in your knowledge of how robust logging is a critical component of any properly engineered software project, especially network services of any kind. It's not an either or question, logging is a must-have business/operations concern, whereas a debugger is a nice-to-have developer concern.

> Debuggers are incredibly useful in tracking certain things down and don't make you write and then remove a ton of logging statements.

You shouldn't be writing and removing a ton of logging statements, logging should be a planned and permanent part of your application from the beginning with appropriate severity labelling for debugging as well as run-time analysis purposes. If you want to use a debugger, that's fine, but a debugger is not a replacement for logging.

> Sometimes logging is easier, sometimes debugging is, and not just for "junior devs".

As I already stated in this comment, that's a false choice, logging should be the minimum, the debugger is there if you really want/need it. I never stated that the debugger is only for junior devs, I said I'd be concerned if a non-junior dev consistently relied on a debugger for solving problems in code, which is not at all the same thing. The use of a debugger is appropriate at any experience level, but generally speaking, the debugger is a slow troubleshooting tool that is best suited for exploring code flow or unusual bugs that seem to defy bedrock assumptions about how the application should be functioning. They are not the best tool for everyday bugs and troubleshooting.


I agree that debuggers aren't always the right tool. Use it only when you have a reproducible bug configuration running on your desktop.

There are fancier setups than "print statements", like binary lock-free logs to circular memory maps. But in essence, print statements, yes.

And heh, I just realized that if you're using a debugger with reversible execution tracing, you're using EXACTLY a binary log file.


  > Based on this, it's hard not to state that current
  > Node-developer are the new PHP-developers: 
  > Unsophisticated, completely unable to see when
  > the tools at hand are lacking, and happy with a
  > with whatever they can get running.
Some Node engineers do use debuggers sometimes, particularly those that came from environments in which this is common (Java, etc). However, many Node engineers I've worked with rely on unit testing, keeping functions very simple and intuition.

Btw the tooling in the Node ecosystem is actually pretty good.


All you've done is move the problem. What happens when the unit test fails and you want to step through the process to see why?

You also seem optimistic, unit test don't catch new bugs, they just test for typos and the bugs you already knew about.


> You also seem optimistic, unit test don't catch new bugs.

You write a new unit test using the data which caused the bug but expecting a non-error state. The error that is being thrown/rejected will have a stack trace you can inspect to find the line which threw. To find the real cause you need to read the code before this to find out how the bad state was created.

If you kept things small and simple, it is not so difficult to work out what went wrong. If you let things grow in complexity too much, you can however end up within a breakpoint/log quagmire.


In the idealized functional world that doesn't exist, maybe.

Programming anything beyond a small app is ultimately managing complexity and often fixing how the various moving parts don't quite work together as you intended.

You simply can't, and shouldn't, unit test that stuff.


>Weird to see people happy to be limited to such stone-age work-flows when fully capable debuggers have existed for almost all proper languages out there the last 30 years.

Even though node has a debugger with breakpoints, etc., an effective programmer will still use logging in situations like the ones in the article. Taking the first example, before he knew that NaNs were causing the problem, setting a breakpoint would have taken forever to reveal anything. You can't set a conditional breakpoint until you know what the condition is. Logging was the fastest way to get useful clues.


I disagree. He simply had to inspect the live DB and see what the state was when someone said the order was wrong.


Yeah this is pure ignorance. There is a time and place for advanced profiling/debugging tools, and there are times where using simple logging to debug things quickly is perfectly fine. You applying debuggers as a hammer to all the problems and all the people is the thing thats weird imho.


In some cases here, he's talking about fixing bugs in a production. It's not so simple to attach a debugger to a live application serving 100s of requests. Break and you just 500'd all users.

In others granted he's working locally and probably could have found the problems without logging, but that just comes down to preference IMO.

Node does have a debugger though and recently added official (though experimental) support for attaching the Chrome DevTools debugger [1]. Doing so was doable via 3rd party packages previously.

Edit: updated as author wasn't only talking about in-production.

[1] https://nodejs.org/api/debugger.html#debugger_v8_inspector_i...


>Based on this, it's hard not to state that current Node-developer are the new PHP-developers: Unsophisticated, completely unable to see when the tools at hand are lacking, and happy with a with whatever they can get running.

PHP has had debugging for a long time, PHPStorm is pretty much now the standard in php development and includes full productivity in that area. It also doesn't face the issues web-JS has with pre-processing, post-processing and compilation of JS code that has to have a source map back to the original source.


This is a case of developper ignorance, not missing tools: v8 has an integrated debugger since 2009, and you can interact with it using the Chrome developer tools, probably the most used debugger frontend of all.

There are also debuggers for PHP :) No horse in this race, I write Python.


It also sounds to me like they didn't have any proper unit tests, which is quite a low-hanging fruit for sorting algorithms.

Also, while I agree mostly with you, there are cases where logging is more useful for debugging than using step-through debuggers. However, such problems are usually related to concurrency where a debugger may alter or even hide the problem, not stuff like this here.


Sometimes, there's no substitute for println debugging.

Particularly with real-time, concurrent code where you're interacting with an external system, bringing a thread to a halt in your debugger causes all sorts of false-positive timeout bugs. You get about one shot to break with the debugger, then your state is trashed and you have to start over.


This is absolute garbage. How can you state that users of a language are unsophisticated? You can make the argument that certain languages ALLOW you to be an unsophisticated developer, have lower barriers to entry, or give you enough rope to hang yourself, etc. But your logic here just does not make any sense. How can you call someone unsophisticated for KNOWING something?

I would bet that most developers know more than one language. So what if you develop with Python, C++, and Node? Does the singular fact that you develop with Node make you a shitty programmer?


The biggest hard lessons I've had with Node.js have been around handling errors - when I first deployed https://www.findlectures.com, I was shocked to realize that uncaught errors could take down the whole site. Not handling error callbacks is also a big problem - TypeScript has been an awesome solution though, because it can show compilation errors if you screw up function arguments.


That's not Node.js. That's Express or a similar abstraction.

You can execute everything inside a promise like with Koa, which amounts to something like:

    http.createServer((req, res) => {
      handle(req)
        .then((response) => res.send(response))
        .catch(() => res.send(500))
    })
    
Where `handle` is an async function and thus all your application logic is in async/await space.


It's Node.js - the root of the problem is also Node's strength, which is that there's effectively no stack. You can manage zillions of concurrent connections, but there's no easy way for the system to unwind bad behavior by one of those connections.

In a Java app you except all the way to the request response.

In a Go app you return all the way to the request response.

In a Node app, you have to call your way back to the request response. Or you don't, potentially leaving the whole process in an inconsistent state. The amazing concurrency of node comes at a price.


Domains were Node's answer to that, and it seemed to work pretty well. I adopted the approach for my own web framework (not JS based) and it has been an extremely useful abstraction.

They're soft-deprecated in Node now though, and AFAICT work on a replacement has stalled.

https://nodejs.org/api/domain.html


And in async C# - which has the same "amazing concurrency" - it just works. Because the language will take that exception, and wrap it into a faulted task (promise) for you. So the stack may be spaghetti, but exceptions navigate it correctly same as everything else.


But you're still error handling with `.catch()`. Without that, you'd have an uncaught Promise rejection, which could take down your Node process.


It's common for people to complain about something like a syntax error taking down their whole process, so that's how I read it -- that you're trying to do "too much" catching.


I'm not an expert with​ deploying application servers but shouldn't part of handling lifecycle include the ability for a service to crash and be respawned?

Ie. Be okay if a syntax error crashes your server.


In a "one request per process" model, sure. But if you are handling 1000s of concurrent connections, a syntax error crashing your server means all of those connections error.


If you're comparing to J2EE, ASP.NET, Apache, etc, application servers tend to be big monoliths with lots of features, but Node is much lighter / more modular, so you end up setting that up yourself (that also surprised me)


Yes you should be using a process manager like PM2.


Yeah, I'm happy to admit that I figured out how Node/Express work entirely by doing things wrong, and then fixing my mistakes :)

I came to this after building C#, Scala, and Java webapps, so it surprised me that this these class of coding errors could take down a site (both screwing up the try/catch or not handling promises).

There is probably some room for Node/the language/Express to make the experience better, either way it's something you'd need to know if you're new to the platform :)


That's why you use a production manager like pm2


pm2 will restart the app on crash if I understood correctly how if works.


Something I found surprising was the 1.5 GB limit per process when used on Heroku (https://devcenter.heroku.com/articles/node-concurrency), which afaik can be circumvented elsewhere (https://futurestud.io/tutorials/node-js-increase-the-memory-...).

This can be problematic at times if you need to open a very large number of concurrent connections (crawlers, slack connections etc), and can force you to organize a "cluster" of processes before you really want it.


You can have quite a number of concurrent connections in 1GB of RAM, 10k at least? That seems allright for a single node, and scaling horizontally after that. For something like crawling, which has a lot of time spent on CPU intensive parsing and I with unpredictable times (hitting external service) I would throw that in a background worker from the start.


I do not have the numbers handy, but it was below 10k (by quite a margin), unfortunately.


Wow, working with Node sounds like a huge pain in the ass.


This is always my take away. Quoting from an above post

>>Ie. Be okay if a syntax error crashes your server.

Really? I need to set something up to stop a syntax error not crashing the server

These rapid prototype arguments don't hold either imo. I can knock out quick and dirty java / c# apps plenty quick enough that work fine for their needs. In my forays into dynamic languages there is no rapid development due to all the errors, the lack of IDE capability, the compiler replacing tests I have to write


I have a hypothesis - I think elixir,golang and java+vertx are carefully designed, highly productive and high performance frameworks.

However with Reactjs + React Native, you have an unavoidable component of your company that is in javascript (or will have soon). Why would you not do JS based server runtime ? With typescript/flow, you actually have an excellent language with no compile steps. Plus, and probably the most important, you have a cross pollination of engineering talent and time .

I think its the same case with data science - it is much more productive to build a python based data science startup, because of flask+sqlalchemy+jupyter+pyspark+numpy+tensorflow+keras. Yes, you can use scala or java... but you lose that one-language-to-rule-them-all productivity multiplier.

From a quick prototyping point-of-view, i think golang would have theoretically killed nodejs.


Regarding throw and NaN, when the program throws an error, make sure it's restarted! When JavaScript throws, it stops doing whatever it was doing. But the rest of the program will continue to run like if nothing happened. NodeJS does the right thing by "crashing" / exit.

When you asume something in JavaScript, for example that the second parameter in the function is a callback function make sure it is!

  if(typeof callback != "function") throw new Error("Expected callback=" + callback + " to be a callback function!");

  if(isNaN(someNumber)) throw new Error("someNumber=" + someNumber + " is NaN! someState=" + someState);

  if(something == undefined) throw new Error("something=" + something + " is undefined!");


spent 2+ years learning js/nodejs etc I finally turned to PHP for server side, it just seems easier for me to get the job done with php, or it's just me.


Not a big fan of PHP, but it has certainly improved it's performance. Wouldn't be surprised if PHP 7.1 isn't competitive with Node.


I can't help but feel like this reads as Stockholm syndrome. Everything about Node is hard, but I'll keep on struggling.


Author calls it 'emotional' :)


These read almost like Zen koans. Such good stuff.


I agree. I wouldn't quite call it koan-level but the breezy style is definitely attractive to me.


I have had occasion to work on a Node.js based app in the last while. Well actually mostly a React/Redux-based app served out of Node.js, so 90% client-side but ... I think it's great! For quickly hammering something together and getting something bootstrapped and up and running it is so easy and straightforward.

But .. I have this niggling feeling .. as my code develops I'm noticing the expressiveness of Javascript lets me do things that look nice, and impressive but that I know will come back to bite me when it comes to enhancement and maintenance.

In this respect Javascript kind of feels like perl with OO and functional semantics built in from the ground up. It really is a lovely language but I wonder how well a JS-based system will scale over time. I've heard people say "never use ruby in production" and I wonder does the same reasoning apply here.

The argument goes that building apps that use the same language client-side/server-side carries the virtue that you can write "pure" apps - i.e. that share code front-end and back-end. That is definitely something that makes sense, especially if you need shared libraries you won't need to write the same code twice for each end.

But beyond that, I feel the expertise required at both ends is quite different. As a systems programmer I feel that strongly-typed rigid languages are very much the way to go because they give you a better sense of how robust the code is. Typically on the back-end you want to get something to work once, and leave it, so you need to be sure it's right.

My more limited experience working client-side suggests that you need far more flexibility there. Issues are far more easy to spot front-end and the key virtue is to be able to make changes and enhancements quite quickly and you don't have the same stringent code-confidence needs as you do on the backend because the quality requirements are different. Niggles and gotchas can be spotted, diagnosed and worked around on the front-end but on the back-end they become a royal pain.

So this, is what I think Javascript is great for on the front-end. I do love the simplicity of bootsrapping Node.js on the backend and the actual reactive framework for building apps is really cool. But yeah, for systems code "at large" I see limitations there for sure: The same we had with Perl, Ruby and Python. Perhaps what we need is some alternative language support e.g. Haskell or something that gives the same code-confidence, but which can interoperate perhaps with the "pure" javascript libraries similar to how say Scheme and Java can interoperate.


The article mentions synchronous performance, but there are no mentions of optimizations. You can do a lot of optimizations in JavaScript and the VM itself is already well optimized. If your naive implementation is slow, my experience says you can speed it up 100x. Then it's not really worth switching to C/C++ assembly for another 10x performance. Then it's better to take the step to pure hardware.


I would have like more detail on what they were doing with node. Building lots of small apps or one big one? Green fields or brown?


I've only worked on a large side project, but from that experience I have a theory that it is one of the triggers for microservices as a pattern, because the pain of debugging a Javascript server application seems to scale a lot more than linearly.


Feel free to reach out. :0)


The sheer number of responses/comments here (hell, even the article itself) justify Node by community alone in my opinion.

I like the fact that I've been able to follow along as it's matured and this gradual bit by bit learning process has made me a better developer because of it.


Too many lessons learned and arbitrary rules to follow equals flaws with design/language design


What language does not have these kinds of problems? I have encountered them with every programming language.


There are certainly huge differences in the number of gotchas different plaforms have.

I have been absolutely disappointed by Node's tremendous number of gotchas in deployment and massive complexity of build pipelines needed to get around the inherent issues of the platform.

My deployment with Django, for example, have been much simpler to handle.


For your information: to assess what projects you might be referring to, I clicked on your profile, but your hackernews profile points me to a URL with a broken security certificate belonging to Ukrainians, and even when I bypass the security warnings in the browser, I am sent to a page which gives me the message "404 not found".


Hackernewsers was a thing from a few years ago, not his fault it's shut-down.


The above message is purely for the person above's information. I have no way of contacting them off this noticeboard, so I wrote a private message to them about that as a reply, and marked it as such with the words "For your information". As far as it being someone's fault, the profile on news.ycombinator.com is editable, so he or she could edit it as they please. What a nuisance it is to continually have to deal with people who misinterpret what other people have written.


For example, Rust distinguishes between PartialEq and Eq

https://is.gd/kRvoMm

you can't derive Eq (transitive equality) on f64

https://is.gd/FjTcA5

but you can derive PartialEq (intransitive equality)


Unfortunately I do not yet know very much about Rust, but I wasn't referring to the specifics, but to the point that every programming language seems to have quirks and hidden rules.


So just use a programming language with less annoying quirks and hidden rules. Especially when those quirks are issues at compile time, not issues at 3 AM in production.

"And I found a whole lot of references to req.randomThing and even some req.randomFunction() calls. I then proceeded to search back through every single middleware function which had run before, to figure out what exactly was going on."

In a statically typed languages names are bound at compile time, so you can actually jump to the definition of each name using tooling. A JS tool can only make an educated guess.


"I wasn't referring to the specifics, but to the point that every programming language seems to have quirks and hidden rules."


That's just an excuse to say "all programming languages are hard"

Which is true, but ultimately useless


Not entirely useless. For low risk, use the language you know instead of new ones - they will have yet-to-be-learned gotchas.


Take for example Elm. Elm has no runtime errors, the concept just does not exist in that universe. That's a whole series of gotchas that don't exist.


Which "every programming language" are those?


Most (all?) languages have such problems, but the quantities of them are not the same in every language.


I'm seeing a lot of Node hate here, especially for large projects in Enterprises, but I've been watching a lot of Node Interactive talks, and companies such as Walmart, Netflix, GoDaddy, Paypal are switching. so why are they happy with it?


Super interesting the part about converting to SSR and React synchronicity. Thank you!


I just want to thank the author for a very well-written piece. I found it incredibly interesting and really connected with the format/flow of the post. I would love to see similar posts for various frameworks and languages.


Isn't the whole section about Classes just due to the cache mechanism when you use require? I.e. all modules are singletons automatically. Is it really CoffeeScript causing it?


Use elixir on the server side and elm on the client side, done.


> Re: "New Relic doesn’t get it"

Can someone recommend a Nodejs performance monitoring solution that works great?


Sorry to say. Node.js isn't the problem. It is a symptom.

Devs these days are craptastic coming from dev->systems with devops nonsense. Just stop forcing this terrible language into server and js is as fine as it will ever be client side.


so... many... links...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: