Introducing something like the Vavr Try Monad in your backend API has consequences throughout all the layers of your application. This talk looks at motivation issues, and solutions to adopting this style.
5. Overview What about Errors?
Why we don’t like how Spring does it?
How we solve it?
How does it affect Grails artifacts?
6. What about Errors? An error can happen anywhere
We want central error management
Near the point of entry, to provide alternative
response to happy scenario
But this is far away from the error, loss of context
Analyzing the cause is harder
Hard to recover out of context
7. How Spring does it -
try {
An error can happen anywhere
=> Throw from anywhere
=> Basically GOTO
We want central error management.
Near the point of entry, to provide alternative
response to happy scenario.
=> Exception handlers FTW
=> Error case statically coupled to Exception class
But this is far away from the error, loss of context.
Analyzing the cause is harder.
Hard to recover out of context.
=> You won’t have a clue anyway how to recover from
an exception handler
8. How Spring does it -
catch {
Complex, static Exception Hierarchies
Catch, log, and re-throw
● Hunt the logs for error causes
● Goodbye consistent error handling
Catch and swallow
● Who knows where this came from anyway?
● Let’s hope for the best
Throw in Transaction rollback for free
● Checked exceptions become a problem
10. finally { Unchecked Exceptions are not really your friend
Checked exceptions are most certainly not your friend
Most code, unless trivial, is not exception-safe
Expensive to throw
Memory leaks, unclosed files, sockets, partially
written files
Brittle Applications, without intelligent error recovery
Don’t take my word for it
12. What we need Error Handling next to point of entry
Preserve context
Don’t break flow of control, don’t break function
composition
Allow local or global recovery mechanisms
13. Our Solution
Error Handling next to point
of entry
Embrace HTTP status codes, even if your
application does not do HTTP
● OK means OK, NOT_FOUND means Not Found,
even if you’re not a web server
● ErrorContext Runtime Exception and factory
methods.
14. ErrorContext factory methods
ErrorContext is a RuntimeException with:
● code (from HTTP status codes)
● extendedCode (for sub-categories)
● context (for ….. context)
15. Our Solution
flow of control
function composition
Renounce exceptions and embrace return types
● Never let a function throw an exception
● Enter Javaslang (cough) VAVR’s Try Monad
16. Our Solution
flow of control
function composition
Try<T>
Parameterized type that represents either:
● Try.Success<T>: successful invocation,
embedding the return value of type T
● Try.Failure<T>: unsuccessful invocation,
embedding a Throwable
17. Don’t break Flow of Control
Try.of {
}
instead of
try {
} catch() {
}
18. Don’t break Function Composition
Conditional function
composition with monadic
functions:
● map()
● flatMap()
Functions are only composed if
Try object is a Try.Success,
otherwise the Try.Failure is
returned directly.
or...
19. Sidenote ;-)
Function Composition is at the heart of intuitively understanding
what Monads are good for (1-slide challenge)
In classical languages:
● Function Composition is “hardcoded” into the semantics and
syntax of the language
● f(g(x)) means: “first call g(x) and feed the result into f()”
⇒ g(x).map(f), in monads, means “compose”
● In Monad Try, composition means: only compose with f if g(x) is
not a Try.Failure
● In Monad Future, composition means: compose with f when
value in g(x) is available
● In Monad List, composition means: apply f to each element of
g(x)
Functional languages with native monads, have nicer syntax for this:
32. Honest functions The functions announce their return type and promise
not to kick you by throwing exceptions.
In Control Your application can, if needed attempt recovery
close to the source of the error, and still keep the
feature to let errors trickle down into the controller
for handling.
Very simple and
generic Controllers
Thanks to Traits specialized in error handling and
Command objects, the controller methods usually are
reduced to one-liners.
Explicit Transaction
Management
You decide where transactions are rolled back, and
you don’t get rollbacks due to unexpected runtime
exceptions deep in your service layer.
Command Objects
Orchestrate Logic
Your Command objects are no longer dumb Value
Objects but fullfill the function to orchestrate your
use case.