Kentico Xperience Design Patterns: Modeling Missing Data - The Maybe Monad
Tags: xperience, kentico, aspnetcore, csharp
Published: 2021-06-14 12:58:30

---
title: Kentico Xperience Design Patterns: Modeling Missing Data - The Maybe Monad
published: true
description: Learn why the Maybe Monad might be the best way to model missing data in our Kentico Xperience applications.
tags: xperience, kentico, aspnetcore, csharp
series: Kentico Xperience Design Patterns
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/hcusgcjdsp4aozej50g9.jpg
---

In two previous posts ([Modeling Missing Data with Nullable Reference Types](https://dev.to/seangwright/kentico-xperience-design-patterns-modeling-missing-data-with-nullable-reference-types-57dj) and [Modeling Missing Data with The Null Object Pattern](https://dev.to/seangwright/kentico-xperience-design-patterns-modeling-missing-data-with-the-null-object-pattern-3gn8)) we compared approaches for representing missing data in our code and considered the implications that modeling had for how we could handle the missing data.

As we saw through some example implementations, both options have pros and cons 🤔.

Let's quickly review how those approaches work and where they fall short. Then we will dive into my favorite approach for modeling missing data in Kentico Xperience applications - [the Maybe monad](https://www.dotnetcurry.com/patterns-practices/1510/maybe-monad-csharp) 🤩!

## 📚 What Will We Learn?

- [Why nullable reference types and the Null Object Pattern don't quite work](#a-refresher-the-problems-with-our-options)
- [What is a Monad?](#what-is-a-monad)
- [The `Maybe` Monad!](#🏔-the-maybe-monad)
- [How we can use `Maybe` with Kentico Xperience](#using-maybe-with-kentico-xperience)

## 🍃 [A Refresher - The Problems with Our Options](#a-refresher-the-problems-with-our-options)

### ❔ Nullable Reference Types

While I do think we should [enable nullable reference types](https://agirlamonggeeks.com/2019/10/20/how-to-turn-c-8-nullable-reference-types/) in our Kentico Xperience applications 👍🏾, trying to model our data with this language feature alone can lead to confusion 😵.

Let's look at the example `HomeViewModel` below:

```csharp
public class HomeViewModel
{
    public string Title { get; set; }
    public ImageViewModel? Image { get; set; }
}

public class ImageViewModel
{
    public string Path { get; set; }
    public string AltText { get; set; }
}
```

We can see that `HomeViewModel.Image` is nullable, so the C# compiler (and our IDE) can alert us to places in our code where we don't first check to see if its value is `null` before accessing its `Path` or `AltText` properties...

If we are unfamiliar with this application, we might look at the code above and ask "But, why is it nullable?" 🤷🏽‍♀️

The LINQ method `IEnumerable<T>.FirstOrDefault()` can also return `null`, but does a `null` value returned here, have the same meaning as a `null` value on one of our View Model's properties? LINQ was not designed with our data model in mind, but the `HomeViewModel` class is specific to our content model - it feels like these two uses of `null` _should_ have very different meanings.

> I find that `null` is great for fixing the "All reference types are a union of `null` and those types" problem, but I don't find it to be the most descriptive technique to represent the data specific to our applications.

As we start to annotate our code with nullable reference types, we'll also discover that `null` is kinda unpleasant 😣 to work with.

If we try to work with a reference type variable or property that is nullable, we have to constantly add checks in our code to tell the C# compiler that within a block of code, we know the value isn't `null`:

```csharp
HomeViewModel vm = ...

// vm.Image might be null

if (vm.Image is null)
{
    // vm.Image is definitely null

    return;
}

// vm.Image is definitely not null

string altText = vm.Image;
```

These checks add complexity to our apps for the sake of protecting ourselves from the dreaded `NullReferenceException` 😱.

It would be great if we could work with our 'empty' values in the same way as our 'not empty' ones and not have to have all these guards! It would also be nice if we could represent their 'emptiness' in a way that felt closer to our data model - not using a low level language feature.

### 🧩 Null Object Pattern

The [Null Object Pattern](https://martinfowler.com/eaaCatalog/specialCase.html) lets us treat an 'empty' value of a type as a 'special case' of its type.

From the previous post in this series, we came up with the following example:

```csharp
public record ImageViewModel(string Path, string AltText)
{
    public static ImageViewModel NullImage { get; } = 
        new ImageViewModel("", "");

    public bool IsEmpy => this == NullImage;
    public bool IsNotEmpty => this != NullImage;
}
```

We've move the representation of 'empty' or 'missing data' into the type itself, which means all of our APIs, properties, and variables can avoid adding the null reference type annotation when using this type:

```csharp
public class HomeViewModel
{
    public string Title { get; set; }

    // notice no '?' on ImageViewModel
    public ImageViewModel Image { get; set; }
}
```

Instead we'll use `NullImage` property:

```csharp
var home = contextRetriever.Retrieve().Page;

var cta = retriever.Retrieve<CallToAction>(
    q => q.WhereEquals("NodeGUID", home.Fields.CTAPage))
    .FirstOrDefault();

var viewModel = new HomeViewModel
{
    Title = home.Fields.Title,
    Image = cta.HasImage
        ? new ImageViewModel(cta.ImagePath, cta.AltText)
        : ImageViewModel.NullImage // takes the place of null
};
```

Now, we don't have to guard against `viewModel.Image` being `null` to interact with it 👏🏻, and if we want to know if it is our 'Null Object' (empty) we can check the value of `viewModel.Image.IsEmpty`.

Despite these benefits, we've unfortunately swung in the complete opposite direction of null reference types and brought the 'empty' value logic into our type, making it more complex.

Even worse, we need to duplicate this logic for every type that represents data that might be missing in our application.

## 🧩 [What is a Monad?](#what-is-a-monad)

We would really like something outside of our `ImageViewModel` class that lets us represent missing data like null reference types, but in an unambiguous way. This approach also should allow us to work with those 'empty' data scenarios without doing gymnastics 🤸🏿‍♂️ to check if the data is there or not.

The answer to our requirements is the `Maybe` monad, a container for our data that lets us operate on it as though it exists (no conditionals) while expressing 'emptiness' (without putting it into our model).

So what is a Monad 😨?

A Monad is a concept from functional programming that sounds complex, and can take a little effort to reason about if you've never seen it before, but don't get scared, we'll take it slow 🤗.

I really like this [description of a Monad](https://medium.com/@nitinpatel_20236/what-does-the-phrase-monadic-bind-mean-a2184f34b2e3):

>  a monad is a design pattern that allows structuring programs generically while automating away boilerplate code needed by the program logic.

This sounds nice, right?

- Developers love _design patterns_ 🤩!
- C# developers know the benefits of using _generics_ 🧠
- And we probably feel like half of our working lives involves _automating away boilerplate_ 🤖

Let's get a little more formal with this [minimalist definition](https://www.dotnetcurry.com/patterns-practices/1510/maybe-monad-csharp):

> A Monad is a container (`Container<Type>`) of something that defines two functions:

> Return: a function that takes a value of type `Type` and gives us a `Container<Type>` where `Container` is our monad.

> Bind: a function that takes a `Container<Type>` and a function from `Type` to `Container<OtherType>` and returns a `Container<OtherType>`.

So, a Monad is a 'container' type, which, in C#, means it is generic on some type `T` and it has 2 methods, `Bind` and `Return`:

```csharp
public class Monad<T>
{
    public T Value { get; }

    public Monad<T>(T value)
    {
        this.Value = value;
    }

    public static Monad<T> Return<T>(T value)
    {
        return new Monad<T>(value);
    }

    public static Monad<R> Bind<T, R>(
        Monad<T> source, 
        Func<T, Monad<R> operation)
    {
        return operation(source.Value);
    }
}
```

`Return<T>` takes a normal `T` value and puts it in our Monad container type. It's like a constructor:

```csharp
Monad<int> fiveMonad = Monad<int>.Return(5);

Console.Write(fiveMonad.Value); // 5
```

`Bind<T, R>` takes 2 parameters, a `Monad<T>` and a function that accepts a `T` value and returns a `Monad<R>` (`R` and `T` _can_ be the same type). It's a way of unwrapping an existing Monad to convert it to a Monad of a different type:

```csharp
public Monad<string> ConvertToString(int number)
{
    return Monad<string>.Return(number.ToString());
}

Monad<string> fiveStringMonad = Monad<int>.Bind(
    fiveMonad, ConvertToString);

Console.Write(numberAsString.Value); // "5"
```

The simplicity of Monads is what makes them so useful 📐. Once you start to work with them, you'll start to see them everywhere - both in existing code and all the ways you can use them in your applications.

### 🦸‍♀️ Friendly Neighborhood C# Monads

If we look 👀 at some C# code we are used to writing, we can recognize 2 of the types as Monads!

Our [favorite C# representation of asynchronous work](https://devblogs.microsoft.com/pfxteam/tasks-monads-and-linq/), `Task<T>` [is a Monad](https://ruudvanasseldonk.com/2013/05/01/the-task-monad-in-csharp) - its `Task.FromResult()` method is the same as `Monad.Return()`.

Also, the always present enumerable type, `IEnumerable<T>` [is a Monad](https://functional.christmas/2019/15), with `IEnumerable<T>.SelectMany()` being the same as `Monad.Bind()`.

Specific monads can have a lot more features, and methods/functions to make them more useful (think of all the extension methods that `IEnumerable<T>` has to make LINQ as awesome as it is 💪🏼!)

---

## [🏔 The Maybe Monad!](#🏔-the-maybe-monad)

Now, let's get to the Maybe Monad and see how it helps model missing data! We can think of the Maybe Monad as a magic box 🧙🏾‍♂️...

![Small cardboard box](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8j95jd0dz0dmnpsmw6s.jpg)
<figcaption>Photo by <a href="https://unsplash.com/@umbra_media">Christopher Bill</a></figcaption>

---

This magic box might or might not contain something.

It accepts commands from us and can change its contents into whatever we want. If there is something in the box, it changes its contents to what we command. If the box is empty, it ignores the command and nothing happens.

We could also command the box to fill itself, with something specific, if it happens to be empty. If it's not empty, it will ignore the command.

The most interesting aspect of the box that it does all this without us needing to open it up to check if there is actually anything inside.

However, once we are finally done changing or populating the contents of the box, we _can_ open it up and look inside...

![Cat in a cardboard box](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kucidcd8wha2hdr4q3yt.jpg)
<figcaption>Picture by <a href="https://unsplash.com/@dnkphoto">DNK.PHOTO</a></figcaption>

---

The benefit of keeping the box closed is that we can give it unlimited instructions without any checks on its contents (unlike accessing data with null reference types).

Also, if we instead wanted to change items from one thing to another, like an apple 🍎 into a rocket 🚀, without the box, that apple would need to be magical (normal apples can't change into rockets 😿). With this box, the items don't need to have special qualities (unlike the Null Object Pattern classes we create).

With this understanding of what Monads are and how the Maybe Monad gives us the power of the magic box we described above, let's look at how we'd use it with our Kentico Xperience sample code.

## 👩‍💻 [Using Maybe with Kentico Xperience](#using-maybe-with-kentico-xperience)

### Maybe + ImageViewModel

My favorite implementation of the Maybe Monad in C# comes from the [CSharpFunctionalExtensions](https://github.com/vkhorikov/CSharpFunctionalExtensions) library. It's well designed and includes lots of extension methods to make working with the `Maybe` type easy 😎.

Let's look at the `ImageViewModel` example again:

```csharp
public class HomeViewModel
{
    public string Title { get; set; }

    public Maybe<ImageViewModel> Image { get; set; }
}
```

We now type the `HomeViewModel.Image` property as `Maybe<ImageViewModel>` which means it might or might not have a value.

Moving to the example Controller action method, we create a new `Maybe<ImageViewModel>` based on the existence of the `CallToAction` page:

```csharp
var home = contextRetriever.Retrieve().Page;

Maybe<CallToAction> cta = retriever.Retrieve<CallToAction>(
    q => q.WhereEquals("NodeGUID", home.Fields.CTAPage))
    .TryFirst();

HomeViewModel homeModel = new() 
{
    Title = home.Fields.Title,
    Image = cta.Bind(c => c.HasImage
        ? new ImageViewModel(c.ImagePath, c.AltText)
        : Maybe<ImageViewModel>.None);
};
```

You might also notice the `TryFirst()` call 🤨. It's and extension method in [CSharpFunctionalExtensions](https://github.com/vkhorikov/CSharpFunctionalExtensions) and a nice way of integrating `Maybe` into Kentico Xperience's APIs to help avoid the `null` checks we might have if we instead used `.FirstOrDefault()`. It tries to get the first item out of a collection - if there is one, it populates a `Maybe<T>` with that value, if the collection is empty, it creates a `Maybe<T>` that is empty.

The `.Bind()` call on `Maybe<CallToAction> cta` is saying 'if we have a Call To Action _and_ that Call To Action has an Image, create a `Maybe<ImageViewModel>` with some values, otherwise create an empty one'.

When creating the `HomeViewModel.Image`, we can see there's an implicit conversion from `T` to `Maybe<T>`, so we don't need to create a new `Maybe<ImageViewModel>` ... C# does it for us.

When the `CallToAction` doesn't have an image, we assign `Maybe<ImageViewModel>.None`, which is our representation of 'missing' data. It's a `Maybe<ImageViewModel>` that is empty.

So far this doesn't look too different from our [null reference type](https://dev.to/seangwright/kentico-xperience-design-patterns-modeling-missing-data-with-nullable-reference-types-57dj#displaying-optional-values) implementation, but the real value 💰 comes with the way we work with our `Maybe` values 😮.

Let's say we wanted to separate out our `ImageViewModel.Path` and `ImageViewModel.AltText` into separate variables. With `Maybe` we don't have to do any checks to see if `HomeViewModel.Image` is `null`:

```csharp
HomeViewModel homeModel = // ...

Maybe<string> path = homeModel.Image.Map(i => i.AltText);
Maybe<string> altText = homeModel.Image.Map(i => i.Path);
```

We magically changed our `ImageViewModel` properties to `string` values without taking them out of the `Maybe` box.

If we wanted to create an HTML image element by combining the `path` and `altText` variables, how could we do that while keeping them in their `Maybe` boxes?

```csharp
Maybe<string> htmlImage = path
    .Bind(p => altText
        .Map(a => $"<img src='{p}' alt='{a}'>"));
```

No conditional, no guards, no checks. We can stay in the happy world of `Maybe` as long as we want, blissfully 😊 ignorant of whether or not there are values to work with.

The `Maybe<T>` container always exists, and exposes many methods to do transformations on the data inside (like `.Map()` and `.Bind()`). If there's no data, the transformations (magic box commands) never happen - but we always end up with another `Maybe<T>`, ready to perform more transformations.

If we ever want to get the value out of the `Maybe` and supply a fallback value if its empty, we can use the `UnWrap()` method:

```csharp
string imagePath = image
    .Map(i => i.Path)
    .UnWrap("/placeholder.jpg");
```

`UnWrap()` is a lot like Kentico Xperience's `ValidationHelper` type, with calls like `ValidationHelper.GetString(someVariable, "ourDefaultValue");`.

### Maybe Some Best Practices

We can mix and match these extension methods however we want, creating a complex pipeline of operations for our data.

We only open the `Maybe` box when we need to turn it into a traditional C# value - in Kentico Xperience applications this will often be in a Razor View where we have to convert/render the value to HTML or JSON.

!['What's in the box' clip from the movie Seven](https://media.giphy.com/media/ge91zAgmwUqLMqiH2c/giphy.gif)

---

Because we don't need to know about the existence of our value until we are ready to render, we should attempt to keep the value in the Maybe Monad for as long as possible. Similar to `Task<T>`, it's common for a `Maybe<T>` to bubble up and down the layers of our application code, since we defer unwrapping until the last possible moment.

The [CSharpFunctionalExtensions](https://github.com/vkhorikov/CSharpFunctionalExtensions) library does support the pattern below (and it's ok to start with when exploring how Maybe works), but I advise against it ⚠ when seriously integrating Maybe in an application:

```csharp
Maybe<string> name = // comes from somewhere else

string greeting = "";

if (name.HasValue)
{
    greeting = $"Hello, {name.Value}";
}
else
{
    greeting = "I don't know your name";
}

return greeting;
```

The Maybe Monad is meant to reduce the number of conditional checks we need to make, however getting the value out of the container can sometimes be a little un-ergonomic. We will have the best developer experiences with them when we go all-in, using expressions instead of statements, and thinking about declarative data transformations instead of procedural data manipulations.

Try this instead:

```csharp
Maybe<string> name = // comes from somewhere else

string greeting = name
    .Map(n => $"Hello, {n}")
    .UnWrap("I don't know your name");
```

---

Here's some real, production Kentico Xperience Page Builder Section code where I use `Maybe` and some of its extensions to both represent missing data and avoid conditional statements by staying in the Maybe Monad box as long as possible:

```csharp
TreeNode page = vm.Page;
SectionProperties props = vm.Properties;

Maybe<ImageViewModel> imageModel = vm.Page
    .HeroImage() // could be empty
    .Bind(attachment =>
    {
        var url = retriever.Retrieve(attachment);

        if (url is null) 
        {
            return Maybe<ImageContent>.None;
        }

        return new ImageContent(
            attachment.AttachmentGUID, 
            url.RelativePath, 
            vm.Page.PageTitle().Unwrap(""), 
            a.AttachmentImageWidth, 
            a.AttachmentImageHeight);
    })
    .Map(content => new ImageViewModel(content, props.SizeConstraint));

return View(new SectionViewModel(imageModel));
```

`Page.HeroImage()` returns `Maybe<DocumentAttachment>`. My data access and transformation code never needs to check for missing data - it's a set of instructions I give to the magic 🧝🏽‍♀️ Maybe Monad box.

If there is no Hero Image, the code to fetch the Attachment data will never be executed and at the end of my method, my `SectionViewModel` will have an empty `Maybe<ImageViewModel>` 👍🏻.

### Maybe Some Rendering

Even in our Razor View, we can continue to be ignorant about the status of our `Maybe<ImageViewModel>` by using the extension method `Maybe<T>.Execute()` which is only 'executed' when the `Maybe<T>` has a value:

```html
@model SectionViewModel

<p> ... </p>

<!-- Maybe<T>.Execute() the Image method defined below -->
@{ Model.Image.Execute(Image); }

<p> ... </p>

<!-- We create a helper method to render the image HTML -->
@{
    void Image(ImageViewModel image)
    {
        <img src="@image.Path" alt="@image.AltText" 
             width="@image.Width" ...>
    }
}
```

The first approach is great if we want to embrace 🤗 the Monad!

Here's another way we can render the Maybe value:

```html
@model SectionViewModel

<p> ... </p>

@if (Model.Image.TryGetValue(out var image))
{
    <img src="@image.Path" alt="@image.AltText" 
         width="@image.Width" ...>
}

<p> ... </p>
```

This one is better if we want to keep our conditional HTML inline with the rest of our markup and have traditional looking Razor code.

Another technique is to use the [Partial Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/partial-tag-helper?view=aspnetcore-5.0) and pass the `Maybe<T>` type to it, handling the conditional rendering and unwrapping logic outside of our primary View:

```html
@model SectionViewModel

<p> ... </p>

<partial name="_Image" model="Model.Image" />

<p> ... </p>
```

All three are perfectly valid choices and each one has pros and cons, so pick the one that fits your use-case!

## 🤯 Conclusion!!

We finally maybe'd... I mean made it 😅!

Reviewing our previous two attempts at modeling missing data (null reference types, and the Null Object Pattern), we saw how they can be helpful but both either fail to model accurately or are painful to work with.

Null reference types impose a `null` check every time we want to access some potentially `null` data, which breaks the logic and flow our of code 😑.

The Null Object Pattern alleviates us from having to make those checks, but requires enhancing, potentially many, models with properties that express their 'is this model's data missing?' nature. This puts a burden on developers and clutters up our model types 😖.

Monads might seem like a scary 👻 functional programming concept at first, but they're actually pretty simple!

The `Maybe` Monad combines both techniques from our previous approaches into a single container type that lets us operate on our data without having to know whether or not it's missing 😄.

By putting all the state that keeps track of whether or not a value exists, in the `Maybe<T>`, we are able to keep our model types simple. Also, by being able to transform and access data independent of whether or not its there, we code that is clearer and reads more like a series of instructions without numerous checks.

The `Maybe` type is most effective in our apps when we leverage it to the fullest, letting it flow through our data access, business logic, and presentation code. Once we get to the Razor View we have several options available for rendering that data.

Of the three options I've covered in these posts, which do you use to model missing data in your Kentico Xperience applications?

Do you have any other approaches you recommend?

Let us know in the comments below 😀.

...

As always, thanks for reading 🙏!

## References

- [Modeling Missing Data with Nullable Reference Types](https://dev.to/seangwright/kentico-xperience-design-patterns-modeling-missing-data-with-nullable-reference-types-57dj) (part 1)
- [Modeling Missing Data with The Null Object Pattern](https://dev.to/seangwright/kentico-xperience-design-patterns-modeling-missing-data-with-the-null-object-pattern-3gn8) (part 2)
- [The Maybe Monad in C#](https://www.dotnetcurry.com/patterns-practices/1510/maybe-monad-csharp)
- [Enabling null reference types in C# 8](https://agirlamonggeeks.com/2019/10/20/how-to-turn-c-8-nullable-reference-types/)
- [What does the phrase monadic bind mean?](https://medium.com/@nitinpatel_20236/what-does-the-phrase-monadic-bind-mean-a2184f34b2e3)
- [Tasks, Monads, and LINQ](https://devblogs.microsoft.com/pfxteam/tasks-monads-and-linq/)
- [The Task Monad in C#](https://ruudvanasseldonk.com/2013/05/01/the-task-monad-in-csharp)
- [Map and bind - A hidden functional concept in C#](https://functional.christmas/2019/15)
- [CSharpFunctionalExtensions](https://github.com/vkhorikov/CSharpFunctionalExtensions) Maybe and Result monad library

---

<figcaption>Photo by <a href="https://unsplash.com/@jordanmadrid">Jordan Madrid
</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

---

We've put together a list over on [Kentico's GitHub account](https://github.com/Kentico/Home/blob/master/RESOURCES.md) of developer resources. Go check it out!

If you are looking for additional Kentico content, checkout the Kentico or Xperience tags here on DEV.

{% tag kentico %}

{% tag xperience %}

Or my [Kentico Xperience blog series](https://dev.to/seangwright/series), like:

- [Kentico Xperience Xplorations](https://dev.to/seangwright/series/8185)
- [Kentico Xperience MVC Widget Experiments](https://dev.to/seangwright/series/9483)
- [Bits of Xperience](https://dev.to/seangwright/series/8740)