Why Domain modeling matters

Nuno Caro
4 min readFeb 8, 2021

--

Domain modeling is the act of translating the business concepts, such as nouns, rules, and structures into a conceptual representation. It will serve as the source to create elements used in the application source code, like classes, functions, data structures, etc.

Domain modeling very heavily relates to Domain Driven Design (DDD) but is not something that should be used exclusively with it. In fact, I would argue it should be used whenever possible.

Domain modeling is not restricted by the programming language used, but it will be much easier to use with a strong static type system. The ultimate feature that a strong type system allows is the ability to verify the correctness of business rules at compile-time, meaning if the code compiles, the rules are enforced.

Strong type systems are usually associated with functional programming, such as F#, Haskell, or Scala. The type systems on these languages not only allow some of the usual trinkets we are accustomed to but can enforce much more fine grained restrictions on types. They allow us to easily express types like positive integers or 50 character strings that we can use to verify correctness at compile time.

As a sidenote, Scala type system is so powerful that is considered by some to be touring complete.

But why am I talking about this? Using languages like Haskell is not for the faint of heart. But wouldn’t it be great to use the type system as our friend in more mainstream languages? I’d like to think so. In fact, I’ll try to illustrate the same concepts, but with Kotlin.

Let’s say I want to model a phonebook and need a structure for each entry. This first example is written in Java just to better illustrate the points we are about to make.:

A Java class for our phonebook entry

Looking at this definition we can conclude some things about the business behind the structure but not much. We can infer the maximum amount of information we can gather in a Card, but not its restrictions besides basic types.

The same Card but in Kotlin

In the next step of the example, we have the same Card model but written in Kotlin. Here we can already infer two more things that are baked into the language itself, mutability and the absence of a value, i.e. nullability. Just by looking at the model we know that all data is immutable and all fields marked as ? are optional.

But what about additional restrictions? For instance, can a name be an unlimited length string? Can a birth date be a future date? Can a phone number be any integer? Right now we would start taking advantage of advanced type system features like algebraic data types but Kotlin doesn’t have those in the language. Nevertheless, it has some other features we can use.

Inline classes are classes that “wrap” other types to add different semantics, but the wrapping stays mostly at compile time. Only in specific situations the wrapper type is actually materialized into a class instance.

For instance, we need a type that wraps a Long to ensure it is a valid phone number. Let’s assume for this example that phone numbers are 9 characters long and positive, which is the specification for Portugal.

With this approach, we have added additional restrictions to Long without introducing any overhead. But be aware the inline classes are not in stable status yet and they still require a public constructor. This last one can be solved with code linters like Detekt, but it is still a cause for bugs. The same can be achieved with regular classes if you don’t mind the wrapping.

Edit: Kotlin 1.4.30 promotes inline classes (soon to be value classes) to Beta status and allows init blocks and private constructors, which we can use to enforce the restrictions.

Lets then update the example with the rest of the inline classes:

Updated model restrictions with inline classes

Now let’s say we want the contacts to be validated so that we keep our contact list as clean as possible. One way would be to add additional fields saying the contact was validated. This is where bugs hide, because then everyone that updates one of the fields, would need to also update the validate flag associated. There is a better way.

Sealed classes are class hierarchies that are known at compile time. It then allows the compiler to perform all kinds of validation including pattern matching. We can introduce a new class that requires users to iterate through all its possible forms and deal with all the cases.

Updated model with validation on contact fields

With this modelling we make domain violations much more difficult since client code needs to handle both when the contact is invalid and when is valid.

In the end what was the point of this exercise and in which ways it can improve our daily routine? The first main advantage is correctness since we lifted up to compile time a lot of issues that could have been detected only at run time.

The second, and not so obvious, advantage is that these models are mostly self-explanatory. With the proper training, event non-techincal people can understand them. This is the first step towards a ubiquitous language and DDD.

This post was heavily influenced by the work of Scott Wlaschin. I'll leave a link to its site since it contains many useful resources, including blog posts, talks, and his book.

I’ll also leave a link to a Github page that talks about sealed unions. It falls out of scope of this post, but it’s another concept inspired by DDD that benefits from what is written here.

--

--

Nuno Caro
Nuno Caro

Written by Nuno Caro

Computer science geek with a splash of party animal.

No responses yet