Simplifying Error Handling with Monadic Approach

Simplifying Error Handling with Monadic Approach

I have been involved in a legacy project that relies on XML files and a local database. My role is to modernize the system by transitioning it to leverage modern APIs and a centralized database for improved scalability and integration. While working on the new codebase, I encountered a challenge with managing error handling across multiple layers of processes. The project consists of several major processes, each composed of multiple sub-processes, and each sub-process can fail, resulting in an early return with an error message for the entire process.

To simplify error handling, I initially implemented the result pattern, which made the error management easier. However, as the number of sub-processes grew, I found myself writing repetitive conditional checks after each sub-process to verify whether the result was successful. This led to the code becoming less readable and more difficult to follow, with numerous if-conditions cluttering the logic.

Here’s an example of my previous approach:


Article content
Previous Code

As you can see, the method is composed of multiple steps, each requiring an error check. With more sub-processes, the method grows vertically, making it hard for anyone reading the code to understand the entire process at a glance.

To address this issue, I started researching ways to improve the readability and structure of the code. That’s when I came across the concept of monads and functional programming. By applying these principles, I was able to refactor my code to be much more concise and readable.

Here’s how the improved code looks:


Article content
After improvement of previous code

Notice the difference? Now the code is more streamlined and easier to follow. The sequence of sub-processes is clear, and the handling of errors is simplified. It’s immediately apparent what steps are involved in the full process and how errors are managed.

How did I achieve this? The key was to ensure that all methods returned a unified MethodResult<T> type, which encapsulates the result, error messages, and additional details in three properties. I had been using this approach from the beginning to handle errors alongside the expected data, so there was no need to rewrite existing function signatures. By leveraging this common return type, I was able to chain functions together, allowing the output of one function to flow directly into the next. This monadic behavior enabled the entire process to be represented as a sequence of operations, with error handling integrated smoothly along the way.

Article content
Return Type of each functions

To enable this, I created custom Bind(), Map(), and GetOrDefault() functions, which handle the chaining and error propagation:

Article content
Definition of Bind(), Map() and GetOrDefault()


I have implemented IApiResponse interface as like MethodResult while working in a Next.js, Typescript project.

Like
Reply

To view or add a comment, sign in

More articles by Md Hasibur Rahman

  • From rows to vectors - the same idea seen differently over time

    Introduction of technology is more for better data maintenance. Data is everywhere.

  • Transformer Architecture (Part 1)

    Attention is all you need! The whole architecture is hidden inside this simple sentence. While reading the whole blog…

  • How I reduced code size by about 85%

    Previously, I wrote an article on this, but it needed an easier explanation. Let's start from the problem first:…

    1 Comment
  • NoSQL

    Ever wonder how does NoSql work? I wondered why they are different than relational database. What made them to be…

  • Interesting Closure

    Closure can be useful in some scenarios. We know that it can wrap something.

  • Remove Element | LeetCode 27

    Remove Element Problem link: https://leetcode.com/problems/remove-element/description/ The problem is pretty…

    1 Comment
  • Object Wrapper in JS

    We know that JavaScript has 7 types of primitives: number, string, bigint, boolean, null, undefined and symbol. As of…

  • Garbage Collection in JS

    When we create functions, primitives, and objects in JavaScript ; we actually consume memory. May be some of the…

  • Object in JavaScript

    In JavaScript, an object is a non-primitive data type that allows for the storage of multiple key-value pairs, making…

    2 Comments
  • কম্পিউটারের কার্যপ্রণালি

    অনেক দিন ধরেই ইচ্ছা ছিলো বেসিক কাজ নিয়ে লেখার। তাই আজ লিখেই ফেললাম। উদাহরণ বা তথ্য নেট আর বই ঘাঁটাঘাঁটি করে লেখা।…

Others also viewed

Explore content categories