Live data from Hacker News

Error Handling in Node.js

joyent.com

1–10 of 96 posts

Re: Error Handling in Node.js

#2
Giant post about the nightmare that is making robust code in node.js. Summary, don't use a language in large projects that makes it so easy to leak errors and exceptions. There's something to be said about the compiler forcing you to declare what exceptions your code can throw to force you to think about this stuff up front.

Re: Error Handling in Node.js

#3
The main conclusion I drew from this is that node.js has three "standard" ways to return/propagate an error, along with "traditional" methods (return code, global errno, etc).

What's the deal? To someone who programs primarily in C and Ruby, this feels like a tremendous complication of the normal programming process.

Re: Error Handling in Node.js

#4
This isn't stuff every programmer should know, it only concerns people who are trying to write complex non-blocking Javascript without async/await (which are already implemented in Babel and proposed for ES7). It also focuses on Node-only idioms which IMHO should be deprecated in favor of ES6 Promises (which Node's LTS release supports natively!)

Re: Error Handling in Node.js

#6

The main conclusion I drew from this is that node.js has three "standard" ways to return/propagate an error, along with "traditional" methods (return code, global errno, etc). What's the deal? To someone who programs primarily in C and Ruby, this feels like a tremendous complication of the normal programming process.

Part of the problem in JS is that there's pretty much 2 classes of functions. Asynchronous functions and synchronous functions. Both are extremely common.

Async/await solves this to some extent, because you can just go back to 1 way of error handling, which is throwing and catching exceptions.

The third way (working with EventEmitter) is an odd pattern, but it's really more for specialized use-cases. Wouldn't really call this standard. Imagine a long-running operation that can occasionally broadcast that a non-fatal error occurred.

A global error number is a terrible idea, and return codes are not just not idiomatic.

So really there's just two: one for synchronous and one for asynchronous operations.

You'd be in a very similar situation with C. I don't know C too well, but I imagine that most asynchronous operations would be done with threads, and for those operations you also can't just return an error code.

Does Ruby have concurrency or async primitives? I don't know it really well. If it doesn't, it's also obvious why you wouldn't have this problem. If it does, how do you handle exceptions in asynchronous operations? To me it seems that Javascript, Ruby, C, PHP, Java are all pretty similar in these regards and JS is not at all unique.

Go gets this right. The equivalent of this ES7 function call in javascript:

await foo();

In go is a straight up regular function call:

foo();

But not waiting for the result in javascript:

foo();

Is actually handled with the go keyword:

go func();

This, to me, is the major difference in the asynchronous model between Go and Javascript. In javascript (with ES7) blocking is opt-in, in Go it's opt-out. Go is by far the saner model for a programming language that relies heavily on 'green threads' / reactor pattern.

Re: Error Handling in Node.js

#7

The main conclusion I drew from this is that node.js has three "standard" ways to return/propagate an error, along with "traditional" methods (return code, global errno, etc). What's the deal? To someone who programs primarily in C and Ruby, this feels like a tremendous complication of the normal programming process.

Node runs all your Javascript on a single thread so it strongly discourages writing f(g(x)) if g is slow or expensive. Instead you write g(x, f) in continuation-passing style so the framework can start g (send a request or whatever), give up control, and do something useful when the result is available (a response arrives or whatever). But if g fails, either f has to expect to receive an error object that came from g, or you need some glue that checks that g succeeded before invoking f.

Eventually Javascript will probably let you write f(await g(x)) and transform one async function into a chain of Promises and continuation functions (await will throw if g fails), but it's not yet a standard part of the language and not everyone wants to preprocess this experimental dialect into something Node can run today.

Re: Error Handling in Node.js

#8
My non-node specific suggestions:

1 - Don't catch errors unless you can actually handle them (and chances are, you can't handle them). Let them bubble up to a global handler, where you can have centralized logging. There's a fairly old discussion with Anders Hejlsberg that talks about this in the context of Java's miserable checked exception that I recommend [1]. This is also why, in my mind, Go gets it wrong.

2 - In the context of error handling (and system quality), logging and monitoring are the most important thing you can do. Period. Only log actionable items, else you'll start to ignore your logs. Make sure your errors come accompanied by a date (this can be done in your central error handler, or at ingestion time (via logstash or what have you)

3 - Display generic/canned errors to users...errors can contain sensitive information.

4 - Turn errors you run into and fix into test cases.

[1] - http://www.artima.com/intv/handcuffs.html

Re: Error Handling in Node.js

#9

The main conclusion I drew from this is that node.js has three "standard" ways to return/propagate an error, along with "traditional" methods (return code, global errno, etc). What's the deal? To someone who programs primarily in C and Ruby, this feels like a tremendous complication of the normal programming process.

I think the main confusion is the callback thing as you can feed a function to get the returned result or emit an event and using another function somewhere else to receive that result. Javascript was designed for browser (GUI) which means its main job was to handle users' actions. So the event system was invented to decouple the "triggers" from the "actions". You can implement the exactly same paradigm in any other languages (actually a lot of GUI SDKs have equivalent facility). And if treat the callback as the return in other languages then everything would be clear.

The conclusion is 1. Throw an exception (which will stop the programm) if it's a programming error. 2. Handle it in place using callback just like you return the error code in other language if that's an operational error (e.g. user didn't input password when login). Emit an error event is really a special case of the callback when you want to handle error somewhere else (maybe globally).

So I think the article is more about when to "throw an exception" vs "return the error" if you take out those javascript special juices.

Re: Error Handling in Node.js

#10
Some of this looks like horrible advice, particularly the defeatist attitude towards what the article calls "programmer errors". Statements to the effect that you can never anticipate or handle a logic error sensibly so the only thing you should ever do is crash immediately are hard to take seriously in 2016. What about auto-saving recovery data first? Logging diagnostic information? Restarting essential services in embedded systems with limited interactivity? This article basically dismisses decades of lessons learned in defensive programming with an argument about as sophisticated as "It's too hard, we should all just give up".

As others have already mentioned, much of the rest is quite specific to Node/JS, and many of the issues raised there could alternatively be solved by simply choosing a better programming language and tools. The degree to which JS has overcomplicated some of these issues is mind-boggling.

Post reply on HN