- Principles:
- Exceptions are a key observability tool; they provide insights into the errors occurring in our apps, so it’s important not to hide them
- Don’t let a problem worsen by ignoring it
- Make debugging easier when a problem has been detected by throwing exceptions generously
- Catch less; throw more
- Don’t catch fatal exceptions (where there’s no valid way to continue execution): crash instead
- Don’t catch exceptions that reveal bugs: fix the underlying bugs! These exceptions are gift:
- Generously throw exceptions to prevent bad things from happening in the codebase (e.g. preconditions like when a function that absolutely needs a populated list is passed an empty one)
- If you throw a built-in exception, choose the most specific one that applies (to make debugging easier)
- Good messages when throwing an exception:
- “[Description of what was encountered.] Did you forget to…?”
- Avoid the jargon the codebase uses and instead use very straightforward language
- Assume users may end up seeing the messages (if only by accident)
- If you’re about to comment “this should never happen” or “we should never get here” or you’re thinking “by the time we get here this can’t be null”, convert that thought into an assertion or exception which documents your invariants with vigilant code
- Avoid swallowing and simply logging errors and continuing execution, since it will take you longer to fix your bugs
- Avoid returning meaningless empty values (like an empty list or null or no behavior at all) and concealing that an error just happened since that will make detection and debugging much more difficult than if you made the tool act like a problem just occurred
- When you aren’t dealing with a fatal or bug exception, you may be facing annoying/vexing exceptions, like when using a built-in parsing method that throws exceptions you can’t easily predict
- Catch vexing exceptions as close to the call site as possible
- So, for example, wrap parsing operations in try/catch blocks when there’s a way to continue
- If there are narrow exception cases you know you can ignore, catch and move on; but don’t swallow cases that could represent an actual problem
- Otherwise, you may be dealing with “act of god” reasons for exceptions like a network blip, a 503 from an api you rely on, a whole external systems going down, eg - don’t hide those!
- Handle exceptions as high up in the stack as you can where you have the most context to provide and the best chance to make good decisions; don’t handle them deep in the call stack where functions don’t have much context and are often reused
- If retrying, only do so in specific cases (e.g. HttpException with a 503) where retrying is highly likely to be helpful
- Go ahead and catch and rethrow exceptions if you want to add extra detail (metadata) to make debugging easier, but make sure you keep passing the original stack trace along with your message by calling
throw
/raise
and notthrow e
/raise e
(which would make the stack trace start on the line where you called that) so you can see where the exception was actually thrown
Original video by NDC Conferences:
This talk was recorded at NDC London in London, England.
Exceptions are powerful and valuable, but we frequently misuse them and destabilize our applications. We fear users seeing an error message, so we swallow the exception, creating troubleshooting nightmares down the road. We fail to check inputs and throw them at all, letting garbage into our databases that ruins our application’s correctness. When we do actually get around to throwing an error, we use unclear messages that mislead and distract or we go overboard and cover our entire codebase with annoying try-catch blocks that make the code impossible to read.
It doesn’t have to be this way! This talk will tell you about numerous exception-related antipatterns and how to fix them. You’ll get practical examples born of real-world codebases that show you how to design your systems in ways that are easy to troubleshoot. If you’re new to object-oriented programming with exceptions, you’ll get a lot out of this talk: you’ll learn how to do exceptions the right way and enjoy safer and more maintainable code.