On 2025-04-29 17:29, Matthew Weier O'Phinney wrote:
* Exceptions should not be used for normal application logic flow. If
the "error" is recoverable and/or expected, use a different mechanism
so you can use standard conditional branching.
As such, there are a lot of situations where I may not want to use
exceptions. Two common ones:
* Input validation. In most cases, _invalid input is expected_, and a
condition you will handle in your code. Exceptions are a really poor
mechanism for this.
* "Not found" conditions, such as not finding a matching row in a
database or a cache. Again, this is expected, and something you should
handle via conditionals.
I don't want to make this into a quarrel, please consider this to be a
genuine question -- I'm trying to understand the viewpoint behind the
need for such "failed result" channel.
I'm considering this scenario: An update request comes into a controller
and passes a superficial validation of field types. The 'troller invokes
an action which in turn invokes a service or whatever the chain is.
Somewhere along the call stack once all the data is loaded we realize
that the request was invalid all along, e.g. the status can't be changed
to X because that's not applicable for objects of kind B that have
previously been in status Z.
In such situations I have found (according to my experience) the
following solution to be a good, robust and maintainable pattern:
Once I find the request was invalid, I throw a ValidationException. No
matter how deep in the stack I am. No matter that the callers don't know
I might've thrown that. The exception will be caught and handled by some
boundary layer (controller, middleware, error handler or whatever),
formatted properly and returned to the user in a request-appropriate
form.
I currently have no urge to return an indication of invalidity manually
and pass it up the call stack layer by layer. Should I want that? In my
experience such patterns (requiring each layer to do an `if` for the
possible issue and return up the stack instead of continuing the
execution) get very clumsy for complex actions. Or have I misunderstood
the usecase that you had in mind?
BR,
Juris