Types to the rescue
I’ve always underestimated types, why should I wrap everything up into a domain specific type? I just need a
This is a brief story about how types are a safety net, protecting you from potential tricky bugs.
What inspired me to write this story was just this line of code:
final case class Counter(home: Int, away: Int)
Hum… this could be quite confusing, it’s easy to swap home for away and vice-versa. So I went ahead and created value classes for it.
final case class Counter(home: HomeCounter, away: AwayCounter)
final case class HomeCounter(value: Int) extends AnyVal
final case class AwayCounter(value: Int) extends AnyVal
Nice! Job done! I just need to go through the compilation errors and that’d be it!
Guess what? It wasn’t that trivial.
Finding invalid test was my immediately win, I knew that someone at some point had set home instead of away, or home in both values, or any wrong possible combination that you could imagine. So when I was going through the compilation errors, I found a good few invalid scenarios.
val homeGoals: Int = 1
match score Goal(Home) shouldBe Counter(homeGoals, homeGoals)
As I was updating unit tests with valid scenarios I was getting failures and at a glance I thought that I was being naive in just replacing values for the correct ones, but it happens that those where valid failure tests. Our business logic was wrong!
Ugh man, what have I done?! Now I have to go through all these complex logic and fix the real problem just because I had the great idea of making a “small” refactor.
But then I realize, this is great! Just by changing types I could see beforehand all the issues without pressure whatsoever :)
After fixing real issues that I found by changing types I have to say that it made all that business logic way simpler and easier to read.
Creating domain-specific types may seem an overhead when we are modeling, but I have to say it’s an investment and the return is bigger than what you would expect.
Hopefully, this brief story encourage you not to underestimate the power of domain-specific types using tags, value classes or whatever fits your purpose.