- we catch all exceptions from the *outside world* by wrapping all async repository methods with the runCatchingExceptions() function
- the rest of our app only deals with exceptions that belong to the domain model
(continued)
- (optional) service classes will catch exceptions and return a Result<Error, Success> type
- (optional) controller classes will use Result type and easily map any errors to user-facing messages
This encourages us to define every possible error state and show it in the UI.
One drawback of this approach is that we now rely on Freezed code generation to define sealed unions for all error types.
Depending on the project, code generation can be slow - though this can be somewhat mitigated:
So far, what I presented is a WIP and there are some things I want to figure out.
- How to apply the same approach to Streams rather than Futures?
- Should we map Stream<T> to Stream<Result<Error, T>> everywhere? Seems complicated in practice.
(continued)
Another issue is that having more than one exception type (e.g. AuthException, DatabaseException) can make it hard to map errors across the different layers.
Maybe it would be best to define just ONE exception type with all possible errors (it's a sealed union after all).
I want experiment more with this topic and find a robust solution that works well without adding too much mental overhead.
Did you like this thread? Anything you would have done differently?
Let me know in the comments. π
There is so much to cover around app architecture, error handling, and domain-driven design.
And I'll try my best to make it justice in my upcoming course.
If that sounds interesting, sign up to get a *big* discount when I open the pre-sale: