Domain modeling obsession
Tags: oop, design, domain, modeling
Published: 2020-07-25 14:55:28

---
title: Domain modeling obsession
published: true
description: 
tags: #oop, #design, #domain, #modeling
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/zjpxqcu2wqfydy7nlkjz.jpeg
---

Hi there, 
today's topic is "**primitive obsession**" and why it is important (to avoid it) in your domain modeling. 

What is "**primitive obsession**"? 

>It is classified as a code smell and it signals the abuse of primitive data types to represent domain ideas. 

Think of a class like this

```kotlin
data class CustomerInfo(
	val name: String, 
	val lastName: String, 
	val age: Int, 
	val email: String, 
	val address: String
)
```

What is wrong with it? 

You could think that it is perfectly fine but give it a second thought: does your domain expert talk about Strings or rather Email Addresses? 

> Types are important in your design because they act as a live documentation of your domain model and rules. 

Consider for example a validation process. I think you all perform some sort of validation of the data coming from the outside world into your domain. 

Let's stick with the email example. 

Suppose you have a function like 

```kotlin
fun `throwing validate email`(toValidate: String): String = 
// omitted
```

or 

```kotlin
fun validateEmail(toValidate: String): Validated<InvalidEmail, String> = 
// omitted 
```

What is wrong with those two functions from a domain modeling point of view? 

Well, what is wrong is that from a type point of view nothing is telling us that the validation process produced a valid Email Address. 

Let's try to improve it.

```kotlin
inline class EmailAddress(val value: String)

val validateEmail: (String) -> Validated<InvalidEmail, EmailAddress> = 
// omitted
```
	
Much better now: we have a function that is perfectly sound also from a type point of view. It clearly states that it will take as input a `String` and will give back either an `InvalidEmail` error or an actual `EmailAddress`. (If you are curious about the Validated data type have a look [here](https://arrow-kt.io/docs/0.10/apidocs/arrow-core-data/arrow.core/-validated/))

# Why not being obsessed?

I know what may be critics about this way of designing your domain model: too much of a hassle! 

And that may be even true for Java, where adding a class just to have a wrapper has a cost in terms of lines of code you have to maintain (if you think about it, it is a bit weird to have some penalties adding new classes in an OOP language where classes should be the bread and butter of your everyday programming!)

> **NOTE**: with Java 14 there is the feature preview of **Record**s that, even if intended to give an easy way of representing **Value Objects**, addresses also the problem of wrapper types (even if the ergonomics of records can be improved)

Other critics may be linked to performance penalties related to creating too many classes. 

To answer to this line of criticism: performance, unless it is an outmost prerequisite of your domain (say you are designing a realtime engine or whatever), and even in that case, should be addressed later in the design process, i.e. when you have a design to test for performance, and only with the most analytical mindset: measure performances and then think about performance improvements and of course measure again to test your improvements actually worked.

> **NOTE** The `inline class`, shown in the last code example, is an experimental feature of Kotlin, starting from version 1.3. It is designed to reduce the overhead of actually creating real classes and objects at runtime by replacing any instance of the class with the wrapped value. So it is an optimization to let you use wrapper classes to better express your business domain while not having to pay any penalty at runtime.

# Why should you be obsessed?
Should you stop being obsessed at avoiding primitive obsession? No! You should go ALL IN and start modeling to be the more specific you can be at the type level. Consider for example you are modeling an order taking system: your order has a lifecycle and passes through different states. How would you go and model it? 

A first try could be 

```kotlin
enum class OrderStatus {
	PLACED, CONFIRMED, CANCELLED, ... // etc
}

data class Order(
	val id: OrderId, 
	val items: List<OrderItem>, 
	...
	val status: OrderStatus, 
	....
)
```

What do you think? Is it a sound design? Would it be easy to design functions that target a specific order status? Well, no. It would be much easier if you design the entire order as a __choice type__ (or __sum type__ in some circles)

```kotlin
sealed class Order(val id: OrderId, ...)
data class PlacedOrder(override val id: OrderId, ...): Order(id,...)
data class ConfirmedOrder(override val id: OrderId, ...): Order(id,...), 
...
```

With this kind of design, it becomes much easier to define functions that accept orders in a certain state because the order status is encoded in the different choices. 

Ex.: 
```kotlin
fun sendConfirmationMail(order: ConfirmedOrder) = // omitted
```

# Conclusion

What do you gain from being **obsessed** with avoiding **primitive obsession**? Well, you gain a codebase that speaks your domain expert language (the so-called **Ubiquitous language** from DDD circles) and that is less prone to error because you always know what you are dealing with at type level. 


--------
>**DISCLAIMER**: most of the concepts expressed in this article summarize, from my point of view, notions and ideas taken from two books you should read if you have not yet: 
     - **"Domain Modeling Made Functional"** by  Scott Wlaschin
     - **"Refactoring: Improving the Design of Existing Code"** by Martin Fowler