Make impossible states impossible - Kotlin edition
Tags: kotlin, functional
Published: 2020-03-16 18:31:36

---
title: Make impossible states impossible - Kotlin edition
published: true
description: Functional domain modelling for more robust software!
tags: kotlin, fp, functional
---

Sometimes called "functional domain modelling", there are a bunch of articles and videos titled like that but I haven't found a Kotlin edition, so took the chance and hope it's useful :)

Let's state our goal clearly again: **make impossible states impossible**.

What does that mean? In a statically typed language like Kotlin, it means we want to leverage the compiler to ensure that we can only have valid models so that it's impossible to have incorrect cases. In other words:
- Use the type system to describe what is possible or not. If something is not possible, it should not compile.
- Another way to look at it is: use types as if they were tests that you won't need to write. Think about `nullable` types in Kotlin, for example... if it's not marked with `?` you _know_ it's not `null` (unless someone cheated along the way... but you can't control who uses reflection either).

Let's start with an apparently normal example of what could be a user profile in some platform:
```kotlin
const val ACCOUNT_TYPE_BASIC = 0
const val ACCOUNT_TYPE_PREMIUM = 1
const val ACCOUNT_TYPE_PRIVILEGE = 2

data class UserProfile(
    val name: String,
    val age: Long,
    val accountType: Int,
    val email: String?,
    val phoneNumber: String?,
    val address: String?
)
```
What problems can you spot?
- `name`: there could be a number within the string. What about the surname? Special characters? What if it's empty?
- `age`: can anybody live so long to fill a `Long`? Can it be 0? Negative?
- `accountType`: what if someone puts a number that's not in our constants list?
- `email`: an email needs a specific format, but we could write anything in there and it'd compile.
- `phoneNumber`: same...
- `address`: same again...

How could we use the type system to make these cases impossible?

Let's start with `name`. 

### Name

We'd normally have some sort of function that validates the input before putting it into the model, but a `String` doesn't reflect any of those validations. What can we do? How about a type that represents a validated name? Let's explore that.
```kotlin
data class UserName(val name: String) {
    companion object {
        fun createUsername(name: String): UserName {
            // perform some validations on name
            if (name.isEmpty()) throw IllegalArgumentException()
            return name
        }
    }
}
```
So with a specific type we can represent a validated model. But still, there are problems in the proposed solution...
- Anyone can just create a `UserName`, bypassing `createUserName`.
- It blows in runtime if there's any problem

For the first case, an attempt could be to make the constructor private:
```kotlin
data class UserName private constructor(val name: String)
```
But then we get a warning telling us that **"private data class constructor is exposed via the generated 'copy' method"**. Bummer... it's a reported [bug](https://youtrack.jetbrains.com/issue/KT-11914?_ga=2.60279791.356245388.1583944322-2046049152.1549026910) and it doesn't seem to be a priority for JetBrains. At this point for simplicity I think we could just ignore the warning, rely on convention and call it a day... 

Now, if it still doesn't feel right, we could hack it using some interface magic:
```kotlin
interface IUserName {
    val name: String
    
    companion object {
        fun create(name: String): IUserName {
            // perform some validations on name
            if (name.isEmpty()) throw IllegalArgumentException()
            return UserName(name)
        }
    }
}

private data class UserName(override val name: String) : IUserName
```
More verbose than desirable... but it works. Now, there's still the problem of the `IllegalArgumentException`. Ideally we want to handle all our cases and make it impossible to blow up. We could use something like [Either](https://arrow-kt.io/docs/apidocs/arrow-core-data/arrow.core/-either/), or if we don't want to add Arrow we can just use Java's [Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html).
```kotlin
fun create(name: String): Optional<IUserName> {
    // perform some validations on name
    if (name.isEmpty()) return Optional.empty()
    return Optional.of(UserName(name))
}
```
Or since this is Kotlin, you could just make it nullable:
```kotlin
fun create(name: String): IUserName? {
    // perform some validations on name
    if (name.isEmpty()) return null
    return UserName(name)
}
```
For the rest of this post I'll just use the non-interface version for simplicity, but hopefully the point has come across.

### age
Pretty much the same as for `name`, we can create a validated type for it.

### accountType
For this one we can just use a common construct available in many languages: `Enum`.
```kotlin
enum class AccountType {
    ACCOUNT_TYPE_BASIC,
    ACCOUNT_TYPE_PREMIUM,
    ACCOUNT_TYPE_PRIVILEGE
}
```

### email, phoneNumber, address
At this point it should be obvious that these fields share the same problem, so we can create validated types for each of them.

But is that the only problem? Is it possible to have a user that we can't contact in any way? According to the model, this is perfectly valid:
```kotlin
val profile = UserProfile(
    ...,
    email = null,
    phoneNumber = null,
    address = null
)
```
We probably want to be able to contact the user right? So maybe we can generalize all of them as a `ContactInfo`. Is there any way to express that a `ContactInfo` can be "an email, a phone number, or an address"? How would you do that with GraphQL? Hmm... union types? In Kotlin we can represent these with [sealed classes](https://kotlinlang.org/docs/reference/sealed-classes.html).
```kotlin
// for simplicity, assume that we have factory methods for those data classes and the constructors are private... 
sealed class ContactInfo
data class Email(val email: String) : ContactInfo
data class PhoneNumber(val number: String) : ContactInfo
data class Address(val address: String) : ContactInfo
```
In GraphQL syntax this would be: `union ContactInfo = Email | PhoneNumber | Address`.

###  So everything's validated... is that enough?
Our `UserProfile` might look like this now:
```kotlin
data class UserProfile(
    val name: UserName,
    val age: Age,
    val accountType: AccountType,
    val contactInfo: List<ContactInfo>
)
```
Is that OK? Can `contactInfo` be empty? We did say 'no' before, didn't we? We could create a special `NonEmptyList` type (or use [Arrow](https://arrow-kt.io/docs/apidocs/arrow-core-data/arrow.core/-non-empty-list/index.html)):
```kotlin
data class UserProfile(
    val name: UserName,
    val age: Age,
    val accountType: AccountType,
    val contactInfo: NonEmptyList<ContactInfo>
)
```
Now? Hmm... are duplicate `ContactInfo`s allowed? 🤔 What's a data structure that can contain only unique elements?
```kotlin
data class UserProfile(
    val name: UserName,
    val age: Age,
    val accountType: AccountType,
    val contactInfo: NonEmptySet<ContactInfo>
)
```
And that's it! (`NonEmptySet` is non-standard Java/Kotlin, but should be easy to create)

## Conclusion
Making impossible states impossible is about using our data types to represent valid things in our domain, which will ultimately lead to more robust software with less bugs. It's often called "functional domain modelling", probably not because it has anything to do with functional programming per se, but most likely because in the statically-typed functional world we strive for "total functions", which are those that consider all possible inputs and outputs.

Just asking yourself the question of "does my model allow any illegal state?" will get you a long way!

Some resources you can check:
- [Design for errors - An introduction to Domain Modeling with a bit of Arrow by Ivan Morgillo](https://www.youtube.com/watch?v=1pEffDww4-Q)
- [Scott Wlaschin - Talk Session: Domain Modeling Made Functional](https://www.youtube.com/watch?v=PLFl95c-IiU)
- [Making Impossible States Impossible" by Richard Feldman](https://www.youtube.com/watch?v=IcgmSRJHu_8)

## Bonus
When Kotlin finally gets [inline classes](https://kotlinlang.org/docs/reference/inline-classes.html), we'll be able to have zero-cost abstractions.
```kotlin
// this needs a data class to wrap a String
data class Name(val name: String)

// inline classes are basically the underlying primitive,
// verified by the compiler
inline class Name(val name: String)
```