
Mistakes Node.js Developers Make - shawndumas
https://www.airpair.com/node.js/posts/top-10-mistakes-node-developers-make
======
nnq
> Since Node.js runs on a single thread, everything that will block the event
> loop will block everything. That means that if you have a web server with a
> thousand connected clients and you happen to block the event loop, every
> client will just...wait. Read more at
> [https://www.airpair.com/node.js/posts/top-10-mistakes-
> node-d...](https://www.airpair.com/node.js/posts/top-10-mistakes-node-
> developers-make#z8vI87iR0ts5wKuc.99)

This kind of thing would be big enough for me to just recommend to most
average developers to just stick with PHP or whatever they are using now. At
least the one-thread/process-per-request shared-nothing architecture
successfully mitigates the effects of unavoidable developer stupidity (or of
"code you've pushed to production without review after more than a couple
beers" if you want to put it more 1st person...).

Simply because: 1. bad code will inevitably be written, 2. bad code will
inevitably end up, among other things, blocking the event loop, and 3. the
application will need to keep working speedly, form the user's perspective,
despite having bad code sprinkled in it.

Isn't there any "automagic" way to prevent this from happening with node?
...something like, if a request takes more than XXX ms, than at least start
handling new requests in new threads?

~~~
LewisJEllis
"You're too stupid to handle this, just stick to PHP" \- really?

If a developer can't grasp Node well enough to avoid blocking the event loop,
I certainly wouldn't want them trying to handle a thousand connected clients
with PHP!

Anyway, to answer your question - within a single node process no, not really.
If something on the event loop goes into an infinite loop, timeouts will be of
no use, and all other open requests are gonna be toast. This is just a
downside to cooperative multitasking.

~~~
XorNot
Seriously. Blocking the event loop isn't "an accident that can happen" in node
- it's a pretty fundamental mistake.

~~~
esailija
Using any CPU is a fundamental mistake?

~~~
nilliams
People are talking about accidentally blocking the event-loop, e.g.
accidentally creating an infinite loop, not 'using any CPU'.

------
nailer
Rad list - I'm going to use your 1.2 automatic browser restarts via SSE trick!

Re: 1.1 automatic server restarts (for crashes etc) there's no need for
forever / supervisord / nodemon on current Linux: make a .service file for
your app and it will automatically restart if it crashes, on all major
distros.

    
    
        [Unit]
        Description=My app
    
        [Service]
        ExecStart=/var/www/myapp/app.js
        Restart=always
        User=nobody
        Group=nobody
        Environment=PATH=/usr/bin:/usr/local/bin
        Environment=NODE_ENV=production
    
        [Install]
        WantedBy=multi-user.target
    

From: [http://medium.com/@mikemaccana/how-i-deploy-node-apps-on-
lin...](http://medium.com/@mikemaccana/how-i-deploy-node-apps-on-
linux-2014-edition-309d606219ca)

~~~
silverwind
I'd add something like

    
    
        After=network.target
    

in the [Unit] section, or you could be in for a bad surprise after a reboot,
when your service tries to start before network comes up. Also, I doubt that
systemd is available on 'all major' distros.

~~~
nailer
Cheers will do. Re major, Red Hat, Ubuntu, Debian and SuSE current stable
releases all have systemd. That said AWS Linux doesn't have it.

------
MichaelGG
What's up with node people packaging every function into a module? How can
anyone think that a clean build needing to pull in a dozen thousand files and
taking twenty minutes is a good thing?

Why have a, say, sha1 module instead of a general crypto one? I've seen at
least one module that wasn't more than ten lines of actual code. It's
packaging JSON and "tests" were far bigger. It was something trivial that
should be in a stdlib.

~~~
mattdesl
There are a lot of reasons to break modules into really tiny pieces, even if
they are only a dozen lines or less. Some benefits:

\- a terse and frozen API (like "domready" and "xtend") does not end up with
the scope creep and bitrot that monolithic frameworks and "standard libraries"
tend to carry

\- it encourages diversity rather than "this is the one true way"

\- it generally leads to less fragmentation overall (and tighter and more
robust apps)

\- each piece can be versioned, tested and bug-tracked independently

\- once you get used to it and start finding modules you like, it can be
incredibly easy to prototype and rapidly iterate with existing solutions. My
100+ modules are in a similar domain (graphics) and my efficiency for
prototyping has improved because of them.

\- it is better for reusability. If you have an algorithm that depends on
jQuery or another monolithic framework for just a single function, it is hard
to reuse. (ie version issues, bundle size)

It took me a while to come around, but npm has really given me a better
appreciation for small modules. :)

~~~
STRML
Just to add to your list, small modules are incredibly useful for
browserify/webpack apps. For example, if I just want to md5 some strings and
do a `require('crypto')`, I've just pulled about 100 KB of code into my app.

Instead, I can find some simple md5 lib (in this case I used one called "js-
md5"), and get the same functionality in about 3KB.

It seems a lot of Node projects have gone the small module direction. Given
that npm is a package manager that (mostly) works correctly - which is so much
harder than it sounds - we can actually use small modules in our app to little
detriment.

Yeah, an npm install might take a little bit longer than you'd like, although
it's really not that slow. The duplication of modules isn't really an issue in
server-side apps, and in webpack apps you can dedupe code pretty easily with
webpack.optimize.DedupePlugin + gzipping, so it's not an issue there either.

~~~
MichaelGG
That sounds like poor tooling in JS, something solved by say, linkers, in
other systems.

And I'm not exaggerating about build times. A simple grunt build doing some
basic template stuff would take about 20 minutes. The majority of that time
was bringing in the ~13,000 files a rather simple static website needed to
build. I ended up tossing the idea of independent builds and just made a
persistent build machine that symlinked in node_modules. I've got a million
lines of C program that takes less time to fully compile and link.

~~~
mattdesl
I would be curious to see what kind of tool could do this. It sounds like
"tree shaking" (like dead code removal) which may be possible in the far
future with ES6 imports. I imagine it would further add to build times.

Not sure how your rant about grunt tasks and templating relates to small npm
modules. A 20 minute build time sounds like something was vey wrong. My
browserify (incremental) build time is < 100 ms which I can handle.

~~~
MichaelGG
Yeah perhaps current JS tools can't do dead code elimination because of the
highly dynamic environment? Each module could provide some metadata on what it
actually needs. I only target JS via cross compilers so I've never dealt with
this problem.

The small module system ends up requiring a ton of files, which is slow.
Incremental builds don't really apply to a clean build server where you are
basically doing "git clone ... && make". The actual processing isn't my
complaint, just the enormous overhead npm's style imposes. I mentioned grunt
since just having that plus uglify or so ends up bringing in 13k files or
something.

------
hacknat
These were great ideas, but blocking the event loop could have been discussed
more.

Great suggestions on how to profile, but some examples of how to write code
that doesn't block could have been given (for example, spawning a child
process to do a continuous set of discrete tasks).

Additionally, node's limits should be discussed. If a specifically intense
compute task requires a lot of input and will also generate a lot of output
(depending on how frequently this task occurs), that's where node starts to
really get clobbered and the solution may be very difficult.

~~~
alessioalex
Thanks for the suggestions. Indeed I could have elaborated more on the
subject, but I was afraid the article would be longer that needed. I'll keep
these in mind for a future one though.

------
jdp23
I'm seeing an Application Error -- An error occurred in the application and
your page could not be served. Please try again in a few moments.

How meta.

~~~
gnarbarian
I also found irony in this post:

[http://i.imgur.com/GAvWVnN.png](http://i.imgur.com/GAvWVnN.png)

------
pikachu_is_cool
I was half expecting it to say "choosing to use Node.js" with absolutely
nothing else.

~~~
jjangsangy
I was also expecting this. Im glad I didn't though, that type of post doesn't
deserve any attention.

------
wildpeaks
_BrowserSync_ ([http://www.browsersync.io](http://www.browsersync.io)) would
be more useful than _Livereload_ because it also reloads CSS without
refreshing the page and synchronizes navigation if the page is open on several
devices / browsers.

~~~
STRML
Try webpack-hot-loader, you can not only hot reload CSS, but you can hot
reload some JS, most notably React components! It's really a treat when you
see it work, and it's just one more way to tighten up your dev loop.

------
nawitus
>Automating restarts / Automatic browser refresh

I don't think this is very beneficial when your project's complexity grows
enough to require a non-trivial build. It's nice to have for simple projects,
of course.

> Using control flow modules (such as async)

In my experience the async module creates verbose and ugly looking code. In
almost all cases promises are a better solution. Of course, even promises are
pretty ugly as it's a "hack" to solve a problem at the language level. ES7
proposal includes async/await, maybe that'll finally solve this problem.

>Not using static analysis tools

I'd also recommend checking out TypeScript and tslint for complex Node.js
applications.

~~~
esailija
`async/await` is only for sequencing, it's not gonna replace anything other
than `.then` chains. If you have such chains to the extent that you think
`async/await` will solve your problems, you should think very hard if every
item in the chain is truly depending on the previous item in the chain because
you are currently losing a lot of performance to that otherwise. I have often
seen examples using generators and `async await` that needlessly turn fast
concurrent promise code into slower sequential code.

~~~
nawitus
You can sequence multiple async operations with promises quite easily by using
Q.all (of course this depends on the promise library you're using).

Even if async/await will only replace .then chains, that already fixes most of
the issues. Most async code actually consists of .then chains (or just a
single async function call).

Anyway, I agree with your point. Developers need to understand how to use
async/await correctly.

I wonder if async/await could be implemented for grouping multiple async
operations together..

------
_RPM
While this is a great list, it is subjective, and shouldn't be taken
literally. There is no "right way" to do things.

~~~
LewisJEllis
I agree with you in part; there are at least a few entries in the list which
would be better described as "pitfalls" than as "mistakes". But "subjective"
does not describe every entry in the list; there's absolutely no reason not to
lint, test, and profile a production application.

------
icantthinkofone
I often see the complaint that you need a tool to restart node after making
changes. And here it is as the first one of ten top mistakes which makes me
think reading the article might be one of ten mistakes one would make today.

If doing 'Ctrl-C, node file.js' is too debilitating .....

------
funthree
rconsole provides syslog bindings as a drop-in replacement for node's built in
console module along with other useful output (revised console)

If you want to forward your logs somewhere remote you can set that up in your
syslog config

[https://github.com/tblobaum/rconsole](https://github.com/tblobaum/rconsole)

------
thirsteh
Mistakes Node.js Developers Make, or a critique of Node.js?

~~~
tg3
considering every mistake in the list had an accompanying "right way", I don't
think it was a critique of Node.js. Some of these might rightly be called
"Mistakes Web Developers Make".

~~~
thirsteh
Most of the callback spaghetti and event loop blocking stuff is just a
critique of Node.js, not developer ability. Most other languages don't have
these problems.

~~~
jonny_eh
It's a trade off. Other languages don't have this problem but they are missing
the benefit of an all async ecosystem.

~~~
thirsteh
It's not a benefit. Most other modern languages are also async, they just
don't force the programmer to think about it. Go, for example, is just as
"async" when it comes to efficiency as Node.js (more so, actually, since it
can use more than one CPU core.)

The whole notion that node.js (or Python's Twisted) makes everything more
efficient by putting you in an event loop is just a cop-out for not having
something more intuitive like blocking semantics with an evented I/O
scheduler.

~~~
nostrademons
I wouldn't say "most" \- it's basically just Go, Erlang/Elixir, and Haskell
that offer blocking semantics with an eventloop under the hood. If you work in
Java, the "easy" way is to use threads, and you have to think about it if you
want non-blocking IO. If you work in C++, there is no "easy" way, and you have
to think about it if you want non-blocking IO. If you work in PHP, Perl,
Python, Ruby, or Javascript, they are single-threaded by default but give you
basic UNIX concurrency/IO primitives to work with.

~~~
eropple
_> If you work in Java, the "easy" way is to use threads, and you have to
think about it if you want non-blocking IO._

Or you use Play/Akka and don't think about threads. Or Scala streams and don't
think about threads. There's not much thinking about threads going on here. (A
major reason why Go just makes me shrug is that I already have its good bits
within easy reach on the JVM if I want them, and I don't have its bad bits.)

 _> If you work in C++, there is no "easy" way, and you have to think about it
if you want non-blocking IO._

YMMV, but I don't find boost::thread_group and Boost.Asio terribly hard.

Also, you omitted C#, which has some pretty fantastic asynchronous tools that
you don't have to think about at all.

~~~
warfangle
While Scala certainly rubs on the JVM, it's not always possible to use in a
project that requires concurrency...

~~~
eropple
I have yet to see a project running on a JVM (i.e., HotSpot, not Dalvik) where
Scala was _impossible to use_. I have seen many projects with management that
decried its use, but that's a self-caused and self-reparable problem.

And Akka is perfectly usable in Java.

~~~
nostrademons
All software problems are self-caused and self-reparable: if you want to use
Language X and all your infrastructure is in Language Y, you "merely" need to
write an interpreter for Language X in Language Y.

When management decries usage, it's almost always because they're running a
cost/benefits analysis and the costs of using X (including writing language
bindings for code, training programmers on the team, hiring new programmers
for the team, context switching between multiple languages, and dealing with
bugs and corner cases that have been encountered and fixed by other people in
more mainstream languages) outweigh its benefits. Many of these costs are
invisible to the engineer who originally proposed using X.

~~~
eropple
Like I said: Akka's right there. Works in nice, nonthreatening Java.

But the "repair" I was referring to is that a developer can _leave_ rather
than put up with conservative silliness if they so choose (and personally, I
do, my last gig was a Scala one and so is the next). Java shops are not so
rare as to be irreplaceable and any shop seriously worried about hiring
somebody who can work with systems that are by now fairly well-understood
isn't going to be a good place for any decent developer's career.

------
ixtli
another mistake javascript developers make: using %s when it's unnecessary. by
way of example, the author says:

console.log('delay is %s', chalk.green(delay));

where as it's much clearer to say

console.log('delay is', chalk.green(delay));

This works in node as of at least v0.10.33 and chrome, but probably most
modern browsers.

~~~
olalonde
I personally prefer

console.log('delay is ' \+ chalk.green(delay)));

as it is more consistent with non console.log expressions. For example, just
with copy/paste I could replace the above with:

var msg = 'delay is ' \+ chalk.green(delay); console.log(msg);

But it's really just a matter of preference as long as only one convention is
used throughout the same codebase.

~~~
Arnavion
ES6 template strings give you the best of both worlds.

    
    
        console.log(`delay is ${ chalk.green(delay) }`);

------
GeneralError
Why is this post on the front page, what's so special about it?

Read the TOC:

1 Not using development tools

2 Blocking the event loop

3 Executing a call back multiple times

4 The Christmas tree of callbacks (Callback light)

5 Creating big monolithic applications

6 Poor logging

7 No tests

8 Not using static analysis tools

9 Zero monitoring or profiling

10 Debugging with console.log

The author talks about trivial or something that has already been written few
times.

It would be interesting to see if a post with the title "Top 10 Mistakes C #
Developers Make" and comparable content would get just drop the same attention
and encouragement. Maybe if it was written by Jon Skeet...

