Getting to Zero Exceptions
yellerapp.com
yellerapp.com
This isn't really possible in a language that doesn't have type annotations, because in such a language, you can't make any run-time assumptions. All bets are off! Anything could be undefined! Anything might throw at any time!
In a language like Scala, you can almost completely eliminate the possibility of exceptions. You just have to be disciplined about never throwing. If you always use types that represent the possible outcomes of an operation or the valid inputs a module might accept, then you're forced to handle every possibility, and you're forced to eventually converge all your code paths to produce an output value from some bounded set. The more tightly bounded, the better! (Granted, the Scala type system doesn't guarantee that a function won't throw, and some standard library functions do throw, so all isn't perfect.)
Don't want to deal with all the cases right away? No problem, don't throw, just coerce the result to some temporary default value.
If you're disciplined enough in this approach, you'll eliminate all business logic exceptions. You'll still have to worry about errors in the underlying runtime, like OutOfMemoryError, but those you can defer to the operations tier.
I came to dislike this approach because most of the time the error doesn't happen and it's just wasted code that's a bit verbose. So now I'm moving into Akka and going to allow well-defined exceptions to throw that get handled by a supervisor.
It was nice to know errors were handled, but I came to the opposite opinion that exceptions truly are exceptional and errors are an instance of the exceptional taking place. Shrug, the bottom line is being disciplined in error-handling. I know there's varying views on this approach, but I really like crafting method signatures that indicate what they are intended to return rather than `Either` for everything. There's places where `Either` is great like registration where a bad password isn't really an "exception" but user error.
Generally it just involves implementing map and flatMap on your Either type, or something like that.
Disclaimer: not a Scala developer.
I like to check invariants at certain points in my code. Them not being correct is an obvious bug. I would prefer to fail in the most obvious fashion if they aren't correct, which for our production environment is an exception.
I have seen too many apps/modules that throw up and log just because of bad user input. This noise gets tedious to wade through to find the real problems.
-Expected exceptions get turned into metrics
If it's not a bug, mute it in your exception tracker and measure it.
Not understanding the negativity. It was a reasonably well done little blog post, and if you're on, or responsible for, a team where that situation and attitude is occurring it provides some good concise guidelines on how to make life better.
Sometimes if you work with this approach you find that the designers of the libraries upon which you build have, frustratingly, decided to force you to catch exceptions to deal with business as usual, but generally I find that treating exceptions as 'cannot continue' has worked well for most code I've written in the last 12 years.
Fixing exceptions as they come in is great if you've got someone on deck specifically for fixing them, but what happens if everyone is already working on something else? Especially if that exception is something that is relatively unimportant? The idea of setting aside time for working on it is much better. I like to do a refactor Friday and work specifically on this type of goal.
As the article points out, the trick is to get it into your blood -at the start-. If it feels like fixing exceptions takes all your time it's probably because you have let a lot of them creep in.
How many known exceptions do you introduce per sprint? It should be zero; nothing new that you're writing should be creating an exception, that isn't fixed in the sprint.
So what's left? Exceptions that are uncovered outside of the sprint. That is, you had a feature written, tests for it written, QA test it, client demos show it off, and any exception you saw you fixed already. So outside of all of that, where can exceptions even occur? Well, after release, obviously. Weird race conditions, deviations off the critical path, users doing unexpected things, etc. But the frequency of those should be pretty low. Maybe one, two a sprint, max? Surely you can take the time to dig in and fix those without causing the sprint to slip.
Now, as the article also mentions, when you start getting a huge, complex codebase (either due to time, or team size), this gets harder. More complexity = more edge cases. That's one of the reasons to reduce complexity wherever possible, to isolate functionality as much as possible. And this also assumes you have a development process that has you delivering every sprint, and having the stuff used. If you're doing some waterfall "we'll code like crazy for the next year, then test, then deliver", yeah, you probably can't do it. You already said the feature was done; no time to fix that bug! Sorry.
Tada! No exceptions! (Of course, this is the worst possible thing to do.)
It's kind of cheating because Smalltalk exceptions were mostly just ordinary Smalltalk execution. You could start writing your own debugger and be browsing stack traces in a matter of minutes.
Windows 3.1 even shipped with something that basically did just that: https://blogs.msdn.microsoft.com/oldnewthing/20150717-00/?p=...
But of course that doesn't make exceptions go away, you just save on stack unwinding (if you discard the exception), there is still a pretty big overhead.
What you care about eliminating are the ones that happen a lot, or the ones that happen immediately following a release or feature flag being turned on.
If you aren't measuring or capturing things in a reasonable way, that's where you'll feel tons of pain. Otherwise I agree with a few of the comments; getting to zero is a noble goal but perhaps not the point.
try {
// all your code...
}
catch (Throwable t) {
}
No Exceptions there!I think we could take it a step farther and say certain kinds of exception should never occur and should also never be ignored, like NoMethodError / nil pointer exceptions.