Cleaner Exception Handling in JavaScript
Functional Programming is a programming paradigm where programs are constructed by applying and composing functions. So we give a function zero to many inputs and it returns one output.
Exceptions are when something exceptional or out of the ordinary happens, like a “FileNotFoundException” from a file IO library and “undefined_column” from a database library.
Exception handling or catching is the process of responding to the occurrence of exceptions (breaks the normal flow of execution due to errors). To prevent your program from terminating abruptly, we need to catch exceptions.
Let’s say a function performs some side effect operation like performing some IO communication with an API, database, filesystem, etc. There is a possibility that an error will occur and an exception will be thrown.
What’s to follow is an explanation of how we might handle exceptions in a more functional way, making the code easier to read and reason about.
Let’s say we have 2 services, a database, and a notification service.
To use these services we need to use them within a try-catch as follows:
The notify and saveData functions have 2 return paths. Either it returns the expected response or throws an exception when something unexpected happens. The calling code needs to know that these functions might throw an exception. This is a problem in itself as JavaScript does not force you to declare that the function might throw an error. We have to know or look inside the function.
Instead of throwing another exception let’s return an error to only allow for only one return path.
This further complicates things because the shape of the return result is inconsistent. The function now returns data or an error. The calling code would need to do some sort of type checking to determine if the function returned an error or the expected result of data.
Let’s try something else. Changing the shape of the return might help?
This is an improvement as we only need to check for truthy or falsy values.
Let’s try a more elegant and functional way. Let’s use a monad.
In functional programming, a monad is a type that wraps another type in a standard consistent way. It also has a standard way of unwrapping that type.
In our case, we’ll use Either monad of the monet package(there are many more like this out there)
What does the “Either” monad do?
Either (or the disjunct union) is a type that can either hold a value of type A
or a value of type B
but never at the same time (Left or Right). Let’s change our return statements once more.
We now use Either to wrap the response in the Right box and error in the Left box.
Let’s check out how we would now call these functions:
Because these functions now return monads, we can now chain them. The nice thing about this method is that if an error occurs anywhere in the chain, the flow will abort just returning that error as illustrated by a programming concept called railway orientated programming.
After we call these functions, either we unwrap the Right using the map block or the Left using the leftMap block but never will they execute at the same time.
Conclusion:
Using a monad like Either allows us to more elegantly handle exceptions in a more functional way.