Alternative perspective - focus on the exceptions and what they represent to the exception's source, rather than try..except
.
Eric Lippert in his BlogBlog describes 4 broad categories of Exceptions, summarised below.
Fatal
- Definition: Fatal exceptions are not yor fault, and you cannot sensibly clean up from them.
- Examples: Out of memory, thread aborted.
- Resolution: Don’t catch; let them crash the program.
- Design: Don’t ever throw fatal exceptions directly.
Boneheaded
- Definition: Boneheaded exceptions are violations of the API, and are bugs in your code.
- Examples: Argument is null, index out of range.
- Resolution: Don’t catch; fix them in the code.
- Design: Use code contracts for boneheaded exceptions; do not document the specific exception type.
Vexing
- Definition: Vexing exceptions are due to bad design decisions, thrown in non-exceptional situations.
- Examples: Parsing errors.
- Resolution: Avoid calling vexing functions; if not possible, catch the vexing exception.
- Design: Don’t ever throw vexing exceptions.
Exogenous
- Definition: Exogenous exceptions are from unpredictable, external influences.
- Examples: File not found, resource already in use.
- Resolution: Always catch and handle.
- Design: Throw exogenous exceptions as necessary; document the specific exception type.
Obviously this just focuses on the exceptions themselves there are other important considerations around code which uses exceptions, including:
- If any type of exception cannot be gracefully handled and recovered, ensure the full exception information is logged, including as much information around it as possible.
- If a framework you're using doesn't record unhandled exceptions, include a top-level 'catch-all' near
main
which can generate a crashdump with that information. - Use unit tests to assert when exceptions are expected to be thrown and when they are expected to be handled.