My Sooper Dooper Sekrit Projekt has a lot of it and it’s starting to annoy me. I am going to adopt a new pattern to help.
Here’s an example of the problem. Look at the blocks of error handling in
Now imagine many functions with the same pattern repeated over and over: every call to
couch.get() must be followed by nearly identical error handling code. This boilerplate is a problem for several reasons. It’s a surface for bugs; the error handling is required for application safety, but nothing demands its presence. It clutters the source and makes it harder to read and see what’s going on. As with all boilerplate, spotting minor differences in the error handling from case to case can be difficult. It adds to programmer cognitive load.
Here we’ve introduced some improvements.
We start by wrapping the db get functions. The wrapper functions take three parameters: the input originally required by the getters, a success callback, and a failure/error callback. The wrapper functions include all their own error handling. They look at err and status codes and call their error handlers instead of their success callbacks when appropriate.
putTogetherSomeData() to flow better. It first defines the error handler function that it uses to clean up after one of its operations fails. Then it calls the wrapper functions. The success functions don’t bother with any predictable error handling at all, because they simply aren’t called in conditions that count as pure errors.
The error handler is similar to an exception handler, in that you can define it at the level where it makes most sense to handle the error. Lower levels can just toss it on up. But unlike exceptions and err params, you have to define that function somewhere; you can’t just forget to write the error handling.
Weaknesses: One hand-written wrapper per call. Doesn’t help functions that throw exceptions.
Advantages: If you’re like me, you’ve already wrapped many of your third-party db driver calls to do things like log.
Here we’ve auto-wrapped predictable functions.
Weaknesses: Not every function will be auto-wrappable, because the application might have different needs on different invocations of a third-party call. Not enough data is making it back to the error handler. That callback extraction code is iself boilerplate that needs to be refactored out. I like the assertions, though!
Other approaches to the problem
Promises. See q, a popular implementation of promises.