Xiana is a lightweight web-application framework written in Clojure, for Clojure. The goal is to be simple, fast, and most importantly – a welcoming platform for web programmers with different backgrounds who want to experience the wonders of functional programming! It’s easy to install, fun to experiment with, and a powerful tool to produce monolithic web applications.
In this article, we dig deeper into monads in Xiana – from theory to practice.
What are monads in Xiana?
Theory
Monads are a set of functions and types, where the data type is a container for any type wrapped into a single, general
one, and functions that handle these monadic types.
Practice
The monad type packs any data type into a decorated one. This means with strictly typed languages the developer is
able to use a general interface for different typed parameters, and make a decision based on the decoration. Most of the
monad decorators have two discrete states. Either
, Optional
, Maybe
are monads in different typed languages.
Practice – Xiana
Monadic functions must define their own return values wrapped by the success of function execution. Xiana framework modifies
the execution flow based on the monadic state. When a function returns a value decorated via xiana/ok
the execution
flow continues, else when it’s returned with xiana/error
the flow will be short-circuited, and the prepared :response
will be returned. Xiana handles Exceptions
too, packaging them into xiana/error
.
To sum it up: monads in Xiana are the key of execution flow control.
Why monads?
All applications should have a strategy to handle exceptional cases. Some exceptions are obvious, some are unforeseen.
By using monads we won a general way of exception handling, including recovering from an exception and
programmatically breaking the execution flow.
How?
Xiana is based on monads and it is using interceptors. Our interceptors have three entry points :enter
, :leave
and :error
. If an exception occurs either in :enter
or :leave
state, the framework seeks for the :error
function
to execute it. If the exception is obvious, and the execution can be recovered from the exceptional state, the :error
function still able to return with a xiana/ok
wrapped value, and the execution flow goes forward.
On the other hand, if no exception occurred, but need to stop the execution for any reason (for instance the request
authorization failed) the whole execution flow can be interrupted just by returning a xiana/error
decorated value.
Drawbacks
However, the monadic state management makes the execution control easier, the usage of monads has some drawbacks on it.
The first thing is that you must use it. Every function which is part of the execution flow must return either xiana/ok
or xiana/error
.
And the compiler will not help you out if you miss it. It needs some time to get used to it.
Many times these wrapper functions feel like boilerplate. An extra step to wrap every piece of the code
into xiana/ok
. But you should never forget, it’s explicitly says something went as excepted. This is the happy path,
and if something goes wrong, you are able to mark it.
What’s next?
As I wrote it before, wrapping a return value into xiana/error
means stopping the execution flow, and making the
response from the current state. Right now, there is no way to define a finally
statement for faulty cases. This
feature is on the way with the next release.