Value Objects

This post is part of my Dev rules of thumb series. In them, I leave you with a poster with a few rules I follow for each concept, which you can print out and scatter around your office, and a brief explanation of what that pattern is about. You can also find a PDF of the poster at the bottom of this post, for better quality printing. However, please remember, a dev rule of thumb is a Principle with broad application that is not intended to be strictly accurate or reliable for every situation.

Value Objects

Value objects are sometimes confused with DTOs, however, while DTOs are simple data containers with no significant logic, Value Objects are a “thing”, they represent a cohesive concept; they can wrap multiple attributes and the logic associated with them to fully encapsulate that single concept.

For example, a “Time” class will contain the data that represents the time, but it may also contain logic to return the total number of seconds it represents or a method to give us the time in a specific format.

The data they contain is relatively simple, only scalars and other value objects, but the data graph should not be big, they should not be carrying around entities inside.

Value Objects in a domain might be entities in another domain, and vice versa. If our application is a watch, the Time class is likely part of the domain, however, if our application is an arithmetic calculator, it’s unlikely that Time is part of the domain. Other examples of Value Objects might be Money, Currency, Point, Height, and Color.

It is a good practice to make immutable classes, as much as possible. Value Objects are no exception. The reason is that several places in the codebase can hold references to an object, and they might inadvertently change the object data, introducing bugs.

Suppose we have an entity representing a user, which contains a Date object representing when the user registered in our application. If we want to send an email to that user two weeks later, we can get that Date object, add 15 days and have that date, right? Well, if the Date object is mutable and we add 15 days and then persist the object (as it’s done automatically by ORMs), we have effectively changed the registration date of that user. On the other hand, if the object is immutable, when we add those 15 days, instead of changing its internal data, it will return a new Date object with the intended date: The original object, representing the registration date, stays intact.

Unlike a DTO, the Value Objects mean something, they are not just a container of data, so they have internal rules to decide what is a valid or invalid state. These types of objects are never in an invalid state, they must be validated at creation time and, since they are immutable, they will never change into an invalid state.

Another interesting characteristic of these types of classes, is that, although they might be persisted (ie. to an RDBMS), they are not a specific “thing” in our domain, they don’t have a history, they don’t have an identity (an ID property). For example, if I have an application to manage bike rentals, the bikes will have a history specific to each of them, this means they have an identity, and to access them in a database we will likely need an ID property. However, the Tire class used to represent the amount and size of the tires that each bike uses, don’t have an identity, we don’t care about the specific history of those tires.

Another characteristic worth noting is that when comparing value objects, they will represent the same thing when their internal values are the same, not when their memory reference is the same nor when their ID is the same (they don’t even have an ID). So, when we have two point instances P1(1,3) and P2(5,6) they are clearly different, and when we have another two instances P3(7,8) and P4(7,8) their comparison should say their are the same since they represent the same point, despite being two different instances.

Here’s an example of a Value Object in PHP, representing a point.

The relevant part in the example is the add and equals methods existing (logic associated to the concept) and returning a new Point instead of changing the current one (immutability). The __toString method is there just for convenience of the example, a VO doesn’t need to have such method, in fact, it doesn’t even necessarily need getters.

<?php
final class Point
{
private int $x;
private int $y;
public function __construct(int $x, int $y)
{
$this->x = $x;
$this->y = $y;
}
public function add(self $point): self
{
return new Point($this->x + $point->x, $this->y + $point->y);
}
public function equals(self $point): bool
{
return ($this->x === $point->x) && ($this->y === $point->y);
}
public function __toString(): string
{
return "({$this->x}, {$this->y})";
}
}
$p1 = new Point(1,1);
$p2 = new Point(1,-3);
$p3 = new Point(1,1);
$p4 = $p1->add($p2);
echo $p4 . "\n"; // (2, -2)
echo ($p1->equals($p4) ? 'equal' : 'different') . "\n"; // different
echo ($p1->equals($p2) ? 'equal' : 'different') . "\n"; // different
echo ($p1->equals($p3) ? 'equal' : 'different') . "\n"; // equal
view raw Point.php hosted with ❤ by GitHub
An example of a Value Object

6 thoughts on “Value Objects

  1. If we take PHP as our target language, the VOs can be very easily compared with $vo1 == $vo2 (so == and not ===). PHP does everything for us 🙂

    Like

  2. Thank you for an article Herberto. Value objects play crucial role in encapsulating business logic. Use-cases often involve number of different value objects. We’ve found it tricky to combine them. It seems that once a computation involves two value objects, one of them must expose it’s scalar value. I know some people have a base class that all VOs inherit from so that they can access a “well-known” protected attribute across types. How would you deal with two VOs that are part of the computation without exposing the internal scalar values to each other?

    Like

  3. Thank you, nice blog post 👌🏻

    I would only change __toString() to sth else, at least toString(), but consider it is not really valuable the method name itself. The first reason is, in lower php version you cannot throw exceptions in __toString(), the other one is to think about if it is really needed.

    Maybe add “x()” and “y()” as accessors instead?

    Also there is an interesting post by @Ocramius about this thing.

    Like

    1. I understand and even agree, however, on the other hand, that’s just an implementation detail, a VO doesn’t need to have such method, i used it here just for convenient less verbosity when printing the Point in the example. 🙂
      The relevant part in the example is the add method existing (logic associated to the concept) and returning a new Point instead of changing the current one (immutability).
      In fact, it doesn’t even necessarily need getters. 🙂

      But thanks for your input, maybe i should have explained this in the article introduction to the example.

      Like

Leave a comment