

JavaScript (and Node) Best Practices - NoahBuscher
http://noahbuscher.com/practices/

======
nickporter
The author says that as a rule of thumb, he uses callbacks for every function,
synchronous or not. wat.

When you design an asynchronous function, you're telling your caller that he
can go and do other stuff (e.g. process other requests) while you're fetching
his result in the background. Async functions should never block. If making
everything async was a good idea, then underscore would be async.

The author also mentions that it is node convention to use callbacks. Sure,
that's true. But he's calling his callbacks the wrong way. Node convention is
`callback(error, result)`, not `callback(result)`.

Oh and promises ftw.

Articles like this hurt JavaScript's credibility, and certainly doesn't help
new JS/node devs.

~~~
shawnz
I agree that it is a bit overzealous to say that _every function_ should
return its data using callbacks, but sometimes it makes sense even for
synchronous functions. By making a function which doesn't accept a callback,
you are creating an API that can never be made asynchronous, which could cause
you more work in the long run.

For example, consider a function with a synchronous implementation. It gets
the data from a place that is quick and easy to access, so making it async is
not necessary. But later on, that data gets moved to an external database.
Now, in the best case, every place where that function is used must be updated
to be made asynchronous. In the worst case, every caller of the function, as
well as every caller of those functions, and so on, must be updated. And quite
often, converting synchronous code to async is no small feat.

~~~
nickporter
I knew someone would say that, hah!

I am 100% for making sync functions asynchronous if it's implementation might
have to be async in the future.

In fact, I have done so many times for the exact example you have mentioned.

------
notduncansmith
I really appreciate the spirit of this, but this was super-light and I was
hoping to see a few more fairly common idioms. I also take issue with a few
points, addressed below. His note about logic not going in app.js is one that
I wish more Node developers I worked with would pay attention to: the first
Node project I was thrown on at my current shop, app.js was about 2k LOC
(things have gotten much better since then).

Some I would add:

    
    
      - Prefer === over ==
    
      - Prefer pure functions whenever possible
    
      - Use promises, not callbacks.  Wrap callbacks with promises when necessary.  Do this once, and put that in a module.
    
      - *Learn to use Lodash.*  I've seen so many wheels reinvented you'd think I worked at Firestone.
    
      - *Learn the rest of the ecosystem.*  See above.
    
      - Logic shouldn't go in route handlers. Routes should only orchestrate.
    
      - Learn to love the Array functions.  ForEach, Map, Reduce, Filter: use them.
    
    

I also have some beef with the article's content.

> [...] as a rule on thumb, I always use callbacks for any function,
> regardless of what it does.

Please don't. Callbacks are a (somewhat - see below) necessary evil, not an
idiomatic good. Only use this if what you're doing is actually asynchronous -
talking to the network, reading from the disk, making DB calls, etc. Maybe for
_really_ computationally expensive stuff (see bcrypt), but in day-to-day web
dev you just won't run into that.

> If I know I'm going to be nesting callbacks more than two levels, I'll
> switch over to a package like async or write my own function quene method to
> help me out.

No. Do not do that. If you know you're going to be nesting callbacks more than
2 levels deep, just use the async package. Better yet, use promises from the
beginning and don't worry about it.

> I know I've already made some people angry, and I'm okay with that.

You shouldn't be. If you've made anyone angry, it's because you're putting bad
advice out there. Worse, it's mixed in with some really good advice, making it
all the more deceptive.

Once again, I really appreciate the spirit in which this article was written.
I just wish it wasn't mixing utter nonsense into otherwise sound advice.

~~~
gcr
Why is this bad advice? You haven't quantified any of your points, so I'm not
sure whether there's any merit to either side.

~~~
notduncansmith
Well, I feel like I explained why not to use callbacks everywhere (worth
restating: it leads to unnecessarily messy code). As for why writing your own
shoddy implementation of the async package, do I really have to explain why
reinventing the wheel is a bad idea? If I did it would border on the
hypocritical.

------
hiddentao
On the topic of using callbacks, promises + generators will enable you to do
the same job with almost the same level of performance (see
[http://spion.github.io/posts/why-i-am-switching-to-
promises....](http://spion.github.io/posts/why-i-am-switching-to-
promises.html)) whilst avoiding callback hell and having to perform error
handling in multiple places.

A good Promise library (like
[https://github.com/petkaantonov/bluebird](https://github.com/petkaantonov/bluebird))
even provides mechanisms for writing functions that both return Promises as
well as accept callbacks, allowing your API client to choose how they wish to
use it.

Also, beware of making a function "asynchronous" by simply having it accept a
callback parameter, e.g.:

    
    
      function myFunc(v, cb) {
        someOtherObject.v = v;
        cb();
      }
    
      myFunc(5, function(err) {
        if (err) return console.error(err);
        console.log('call done');
      });
    
      console.log('call started');
    

In the above code, you'll see "call done" before you see "call started"
because myFunc() isn't really functioning asynchronously.

This is yet another reason to use a good Promise library like Bluebird, as it
ensures that even if you wrap a synchronous function inside a Promise the
resulting execution will flow as if it was asynchronous.

------
roskilli
I would also add that callback signatures should always follow:

    
    
      function (err, result) {
        //...
      }

~~~
jimmaswell
isn't it usually just function(e){ and then e might have some kind of
indicator that it's an error

~~~
notduncansmith
Usually, when dealing with Javascript, you'll see function (e) { as the
signature for DOM function callbacks, where e refers to the event object.

~~~
zachrose
Similarly, `function(err, result)` is nice because HTTP handlers often use
`function(req, res)`, where the res is a response object. Fumbling over this
kind of thing while nesting async calls in HTTP handlers is a minor annoyance.

~~~
notduncansmith
You should definitely be using promises. Q is a good library. Don't worry
about performance, I can say with extreme confidence that promise execution
speed is not your bottleneck. In that 0.01% of times where it is, use
Bluebird.

~~~
zachrose
Excellent call.

------
hawkharris
Using callbacks appropriately is the biggest point, I think.

On a related side note, I've started using the Chrome Web Inspector as my only
text editor for front end development. It's great because you can map it to
your project folder, make edits directly and harness the power of breakpoints,
along with the network, console and performance tabs, without constantly
switching windows. Breakpoints, in particular, make it much easier to work
with callbacks in JS. (I do miss the nice syntax highlighting of Sublime, but
Chrome's dev tools provides more powerful features for JS development IMO.)

------
w4rtortle
Commenting the purpose of every function just seems like a messy way of making
up for the mistake that your functions are not written in a readable succinct
fashion that can be easily understood.

I also think it encourages new developers to write messy functions and then
think "that's ok I've described what it does in a comment above, so the next
person will understand it anyway".

------
chunkstuntman
Are there any applications or libraries that you would say follow these
practices really well?

Seeing basic examples was really helpful, but a more expansive project that
employs these elements would make for good reading.

~~~
NoahBuscher
I really enjoy NodeBB's source code.

------
brianmcdonough
Well written, but what I really appreciate is succinct.

~~~
NoahBuscher
Thanks, Brian! I really tried to keep things short, sweet, and to the point.

------
tantalor
"my own function quene method"

Huh?

~~~
notduncansmith
I think he was getting at "queueing" (or just "queue"). Regardless, it's a
wheel that doesn't need reinventing.

