Published on

The value of Value Objects

Authors

Value?

When we face a need to pick a new tool, library or framework, we evaluate it, in the most cases, using software technical perspective. We are technical people, aren't we?

Is it fast?

Is it boilerplate-free?

Does it reduce time from the idea to production?

The same is with Value Objects, a tactical DDD "pattern". Typically, we use "immutability" and "identity-less" arguments.

Immutability gives safer, clearer reasoning.

Identity-less gives comparison advantages.

But in my opinion, the true value of Value Objects lies somewhere else. I briefly mentioned in already in Modeling Value Objects in TypeScript post.

Still, I think it's worth emphasizing this impressive, valuable perspective.

Can you add floor numbers?

One of the well-known properties of Value Objects is taming complexity of Primitive Obsession.

Just as a reminder, this obsession is oriented toward treating, so-called "primitives", as something more than they actually represent.

Imagine that we are in the elevator and we want to go to the third floor. Being "noun"-trained software engineer, we spot "third floor".

Primitive obsession

Primitive obsession is about treating ints, strings, bools as something more than they actually represent.

"Third" means number so it's highly probable we would represent it by int-like type (e.g. number in TypeScript). Because it's a number, right?

What can we do with int? For example, we can add two ints or we can multiply them. They are subjects of some operations, behavior.

Can we add floor numbers? Third floor plus fifth floor gives eighth floor, isn't it?

No, of course not. It is silly. But with int representation, it is possible.

The King of All Primitives

Do you know who is it? Beloved, dreaded, unmerciful string. The type that has vast amount of capacity.

It can represent names, addresses, e-mails, bank account numbers, money, age, serial numbers, phone numbers, words, and so on, and on.

There are certain behaviors that are related to string - for instance getting a substring.

Can we take a substring of, for instance, e-mail? No. We can look for domain.

It's a different language. Another level of reasoning.

I really like a thought exercise - asking myself, each time I see string, either required by a method, function or as a variable - "is it any string?"

There's one meme, I believe that Justin was the author of it, and it expresses exactly what is the primitive obsession:

For those not knowing this notation, String -> String -> String -> String, means this is a function accepting a three arguments of type String and returning type String.

What does the String mean in this context?

Age?

Email?

Your bank account number?

In the pursuit of meaning

The biggest value of Value Objects is that they build the language of your problem domain, giving the meaning to primitives.

They elevate the code into higher levels of reasoning, humbly taking away the details (isn't it called abstraction?).

They open the world of thinking about concepts, instead of primitives, by making them "materialized" in front of our eyes.

Words have meaning and with the meaning behavior and rules come.

Even though we have strings, ints, bools - the concepts are there. If not in the code, then in the writer's/reader's head.

It is the programmer who keeps running the entire simulation that makes primitive types representing underlying concepts.

Then (poor) reader needs to understand the rules, "the physics" of the simulation, so that it can be safely run in the mind.

Creating a concept, out of the code, put constraints on thinking.

In DDD, we think a lot of boundaries. Value Objects do the same - they set up boundaries, in which a certain behaviors and rules are applicable.

For example, we are no longer working with e-mail concept implicitly, constantly transferring the constraints from our minds to the code.

We materialize the concept in the code, deploying the model from the head. And now we don't need to continouosly simulate the rules and behavior. Then we can ask our friends to help us: compiler, runtime and specifications/verifications (what's the difference? Please check "The ambiguity" of TDD)

Contraints liberate

What if we "invert" the primitive obsession? What would we get?

Is it an obsession of concepts? Concepts obsession?

One of the strengths of DDD approach is putting enormous attention on the language, hence Value Objects are something more than what tactical patterns show.

They are effective weapon against the complexity, complexity of reasoning.

Next time, when you spot a string, ask yourself

Question 🤔

Is it any string?