Model the Domain
Create objects that represent domain concepts.
Last updated
Create objects that represent domain concepts.
Last updated
We write programs first and foremost as a communication medium for programmers, and eventually for computers to execute them.
Why do we create higher-level languages ?
It is, arguably, not for performances : languages that add layers on top of the machine are decoupled from the machine and take power from the hands of the developer, such that he cannot write code that will outperform equivalent code written in lower-level language. That's pure logic, but that's measurable.
Hence, when us developers, as an industry, create high-level languages on top of one another, we do it for a very simple reason : enhance expressivity.
Expressivity and higher-level concept allow us to enhance our plane of thinking. When we program in C, we're constantly reasoning in term of memory management and have very little place for thinking about the high-level concepts. When we program in Java, we're relieved from memory management and we raise the level of abstraction.
Same goes for concurrency problems. Dealing with threads is hard. Dealing with coroutines is much easier. It's adapted for a wide range of use cases and help reduce the technical complexity of the product. It leaves less room for errors.
But now, since we have objects that are easy to create, develop and maintain, and who help us create high-level abstractions that communicate behavior, shouldn't we use and abuse it at will and at need ?
Let's look at some code.
What's the problem with this code ? It's between the ":" and the "=".
Yes you, string, i'm looking at you.
What the hell are you doing here ? This isn't a place for you to be.
Why ? Because a string has no meaning for us. It only has a meaning for the computer.
Thus, our email address is terribly weak. It's treated as a simple string, yet it is anything except a simple string. An e-mail address is a with rich behavior.
Don't believe me ? Then tell me...
How would you validate that e-mail address and make sure it has the proper format ?
How would you extract the local part (johndoe) ?
How would you extract the domain ?
How would you ensure the e-mail belong to a specific domain ?
See, it's more than a string, much more.
The same can be applied to many other common values represented as strings :
Urls
Passwords
Names
ISBNs
The list goes on.
In each of these cases, string is a terrible type choice because it's a storage unit, not a type, and certainly not an object.
Have you ever heard of business people talking of strings ?
I certainly haven't.
Hence, emailAddress is dying to be an object. Let's satisfy its needs.
Two patterns are at work here. This is a Value Object maintaining its validity using the Always Valid pattern.
This is elegant, satisfying and very useful. That object can be reused in any program, just as is, and be extremely useful for a wide range of use cases.
Look at this code.
See what this pesky number is forcing us to do ? We know have to use a composed name because that number has absolutely no meaning at all. We can't Abandon Composed Names in this case because otherwise, we'd have no idea what that value stands for !
Moreover, a duration is more than just a number. It has a lot of behaviors inside :
Arithmetic
Comparisons
Conversions
I don't want to add more useless cognitive load to my programming activity. Translating business requirements into code is already a complicated job in itself.
So I want to push that value in an object and forget about it. I want a reliable object to take the burden for me, to grab my shoulder and to tell me "don't worry buddy, I've got this".
Here's what I would do.
Look at this guy.
What's departureAt
? A date.
A date ? Any Date ? So I can set a date in the past, or a date in year 3000 ?
See how demure is that code ? It's so timid it harshly says anything. All I know is that it represent a departure date, without telling me what is a departure date.
What's the cost of increasing the knowledge in our code ? Barely creating an object.
By adding a dozen lines we documented an astonishing amount of behavior (without exaggerations) and gathered the rules of the concept inside an object representing the concept. That's Domain Modeling for you.
By rising the level of abstraction in our program, by which I really mean reasoning in term of high quality objects, we create a domain language.
That domain languages documents the software and express what's possible in our universe and what's not.
It allows us to gather the rules of each specific concept as close as possible to the object, releasing other objects from that knowledge, evermore spreading the responsibilities between objects and keeping knowledge as low as possible. Each object becomes really simple to use and work with.
Do not underestimate the main responsibility of code : to communicate about the domain, to communicate about it's intent, to document the software, to help programmers understand the limits of the system and to reduce their cognitive load.
All of that matters much more than any other considerations.
Some astute software developers may argue :
what about the performances ? By adding layers of indirections, we're at risk of cluttering the call stack !
How mindful to think about the call stack. But here's a question for you : what's the cost of software that's hard to maintain and evolve, hard to understand, for which a lot more developers are required than should be ? How many softwares didn't even reach the light before collapsing under it's own weight ?
What's the cost of a few lost call-stack on machines that can run hundred of gigabytes of RAM ?
Let the numbers talk, and measure before optimizing.
How would you get the canonical address (getting rid of ) ?
That bill Probably trillions.