avatar

Krisztián Gulyás

Posted on 16th March 2022

Monads in Xiana framework

news-paper Clojure | News | Software Development |

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.