> Because (1) most software, and most frameworks, are designed optimistically, thinking almost exclusively about when everything goes well. And (2) because of positive bias we test cases we expect to go well
Yes, this realization finally hit me a few years ago and started to make me reign in my use of exceptions. I realized that exceptions are all about giving priority to the optimistic case in the code - making it as clear and simple and with as little branching as possible. However after seeing projects through a full lifecycle (from initial conception through to maintenance in production) I now realize that the really important code - the code that we spend most of our time trying to figure out in maintenance over the lifetime of the application and whose state is most hard to understand and deal with - is in fact the error handling code and that exceptions focus on hiding that code and making it "disappear" and seem implicit. What seems like a win initially can be a huge loss when you're trying to write a robust system where every possible behavior is explicit and well understood.
Many common problems, especially in network servers, can be solved quite elegantly with an "exception driven design". In those scenarios the exceptions serve as a vehicle to bubble state through multiple layers. Pretty much like an event-framework, except many people don't realize they have that baked right into their language.
A simple example would be a network-server that detects a protocol phase change at the lowest protocol level. By raising a "PhaseChange"-Exception you can quite nicely propagate such an event to the higher layers that need to know about it, without resorting to duplicated/shared state or awkward call-chains that introduce nasty dependencies and then need their own exception handling, and without running into potential synchronization issues.
Yes, this realization finally hit me a few years ago and started to make me reign in my use of exceptions. I realized that exceptions are all about giving priority to the optimistic case in the code - making it as clear and simple and with as little branching as possible. However after seeing projects through a full lifecycle (from initial conception through to maintenance in production) I now realize that the really important code - the code that we spend most of our time trying to figure out in maintenance over the lifetime of the application and whose state is most hard to understand and deal with - is in fact the error handling code and that exceptions focus on hiding that code and making it "disappear" and seem implicit. What seems like a win initially can be a huge loss when you're trying to write a robust system where every possible behavior is explicit and well understood.