Modelling value types in kotlin
In this article, you’ll see how to model value object particularly in kotlin.
Imagine we want to improve below model:
1
2
3
class Customer(id: UUID, email: String,..)
class Order(id: UUID,..)
I had 2 use reason for modelling value type
Type safety
lots of time I want to distinguish between let’s say customerId
and orderId
so that accidental passing of wrong Id can be avoided. the best way is use inline class 1 concept but be careful with it’s stability status.
1
2
3
4
5
6
7
8
9
10
// option #1
inline class CustomerId(val value: UUID)
// option #2
data class CustomerId(val value: UUID)
// option #3
data class CustomerId(private val value: UUID) {
override fun toString(): String = value.toString()
fun asString(): String = value.toString()
fun asUUID(): UUID = value
}
Option 1 and 2 are more recommended where as option #3 is example of over modelling.
I often have tendency to make props as private by default. but when we’re modelling immutable data type. You don’t need to mark props as private.
Represent a domain concept with constraint
Let’s take an example of email
which need to match some fancy regex.
This is bit complicated one especially with kotlin because of language design.
But we have 3 options here:
Use constructor to throw violations 😟
1 2 3 4 5 6
data class Email(val value: String) { init { // if (!isValid(value)) // then throw InvalidEmail() } }
This option is not bad but it has few limitations and such as
- constructor is not honest enough because it can blew on your face
- it can hijack your program’s execution
- don’t use kotlin since well-known design flaw 2 😅
- Use NoCopy plugin 🎯 There is really nice article about NoCopy here
Summary
Kotlin has few limitations but those can be fixed. Always go for more transparent and honest representation.
https://kotlinlang.org/docs/reference/evolution/components-stability.html#current-stability-of-kotlin-components “inline class is at Alpha stability level” ↩
https://youtrack.jetbrains.com/issue/KT-11914 “Confusing data class copy with private constructor” ↩