Skip links

Value objects

July 16, 2015 at 7:49 AM - by Freek Lijten - 6 comments

Tags: ,

I would like to talk about value objects for a bit. Value objects are very underused, very powerful and general good stuff. They might not change your world but they will change, very subtle, a lot of the code you write. I hope to give the shortest possible introduction to the concept and follow up with a couple of example that make me like value objects so much.

Value objects are usually small objects and in the words of Martin Fowler: "Their key property is that they follow value semantics rather than reference semantics." This means their identity is not based on some sort of ID but on their properties.

Two "Freek Lijten" person objects might look the same but we'll need identifiers to be sure that we're not simply dealing with two people with the same name. Two color objects with red however will be the same, we do not need an identifier for those, the color is the identifier.

Value objects are generally (always) immutable. Most things that are modelled as a value object do not change. You can not change the meaning of an amount of Money for instance. You might be able to add or subtract an amount but that will result in a new amount of Money. 10 Euro will always be 10 Euro. opposed to that the person Freek may move, change his name or even gender all the while remaining the same "Freek".

This may seem a very small distinction but is actually very important.

Money

// Mutable, you never know what this Money object 
// is going to be  re-used
$Money = new Money(); $Money->setAmount(1000); $Money->setCurrency(Money::EURO); $Money->setPrecision(2); $Money->setAmount(900); // VS immutable Money with methods that result in new Money object, // (more) error proof and more in line with the actual world. $TenEuro = $Money = new Money(1000, Money::EURO, 2); $OneEuro = new Money(100, Money::EURO, 2); $NineEuro = $Money->subtract($OneEuro);

These are two ways of dealing with money. The first one is mutable. This will cause uncertainty on the value of the Money object. You can never know if it is changed somewhere or by what. In the best case this makes reasoning about this when debugging or trying to understand code harder. Worst case it creates nasty bugs exactly when you don't want it, when dealing with money.

The second example is an immutable variant of money. This type of approach to money also prevents you from spreading calculation logic all over the place. Adding, subtracting, multiplying and comparison are all operations on an amount of money resulting in a new amount of money. No more calculations all over the place, no CalculationService or whatever, just money you can do stuff with. I can not stress this enough, this all may seem like small gains, but it will change your code forever.

Email addresses

Email addresses are another obvious example of values that do not change. At the strangest they dissapear after years of not using your email address. What does change is the email address one considers to be "theirs".

To continue with our email address example, I've seen lots of code that validates email addresses over and over again. This strategy does not pay off once you miss checking a single location. If we introduce an EmailAddress object that only constructs with a valid email address we simply can not forget to check for validity:

if (emailAddressIsValid($emailAddress)
{
   // do stuff
}

// vs 

class EmailAddress
{
    /** @var string */
    private $emailAddress;

    public function __construct($emailAddress)
    {
        if ($this->emailAddressIsValid($emailAddress) {
            throw new InvalidEmailAddress();
        }
        $this->emailAddress = $emailAddress;
    }
    
    public getEmailAddress()
    {
        return $this->emailAddress;
    }
}

Everywhere we receive an EmailAddress object we are guaranteed an actual valid address which we do not need to check anymore.

And more...

Once you get into this mindset you'll find yourself wanting to make value objects for nearly anything. Principally you might want to make a value object of everything, only when you find no use for the object apart from being a carrier of a primitive type should you revert back to a simple primitive type. Almost anything has relations, cohesion or business logic attached to it.

Take the much used trio of firstname, insertion and lastname for instance. They are logically together and there is always stuff with formatting of full names, a complete lastname including insertions and more. So why wouldn't we put them together in a Name object?

class Name 
{
    public function __construct($firstName, $lastName, $insertion)
    {
        // set properties
    }

    public function getCompleteLastName()
    {
         if ( ! $this->insertion) {
             return $this->lastName;
         }
         return $this->insertion . ' ' .this->lastName;
    }
}

But even Id's can be useful as a value object. Even though ID's are generally something simple, at the very least being able to typehint different types of ID's can prevent subtle bugs where ID's are switched (think adding a product to a category). If you're lucky the product id is not also a category ID and vice versa (remember a lot of our id's are integers from an autoincrement column) but if both ID's exist then you will have a very intersting time finding out what happened :)

class ProductId 
{
    /** @var int */
    private $id;
   
    public function __construct($id)
    {
        $this->id = $id;
    }

    public function asInt()
    {
         return $this->id;
    }
}

/**
 * @var int $productId
 * @var int $categoryId
 */
function addProductToCategory($productId, $categoryId)
{

}

// vs

/**
 * @var ProductId $ProductId
 * @var CategoryId $CategoryId
 */
function addProductToCategory(ProductId $ProductId, CategoryId $CategoryId)
{

}

Concluding

All in all I find myself making value objects more and more. just remember the following:

  1. A value object guarantees validity. If an email address is constructed with something else then a valid email address it is no email address. So constructing should fail. If we get an EmailAddress object we now know 100% sure that we consider this a valid address, no additional checks necessary.
  2. A value object is THE location for stuff small business logic. Think formatting of names, adding or subtracting money, etc.
  3. Value objects should be immutable, this will prevent bugs and confusion. It must be clear what a value object represents and what states are allowed.

I feel I need to mention the DDD-course Mathias Verraes though us since he made a lot of concepts that where since long floating helplessly trough my brain very clear. This course gave a huge boost to inspiration and ideas. He gives regular courses, check his webstite. You can also get him in-house which is what we did. Huge success :)

Share this post!

Comments

  1. Bert Van de CasteeleBert Van de Casteele Wrote on July 17, 2015 at 10:10:16 AM

    Hello Freek,

    good article, really makes you think about using Value objects.

    One note though : in your Money example above, does the following code have an error ?

    $TenEuro = $Money = new Money(1000, Money::EURO, 2);
    $OneEuro = new Money(900, Money::EURO, 2);
    $NineEuro = $Money->subtract($OneEuro);

    I think the $OneEuro variable should actually hold a Money object of 100 Amount, instead of 900.

    Just mentioning :)

  2. Freek LijtenFreek Lijten Wrote on July 17, 2015 at 12:19:45 PM

    Good point, corrected, thanks!

  3. PatrickPatrick Wrote on July 18, 2015 at 10:21:45 AM

    Good article, Freek!

    I was still wondering what a simple rationale would be to decide whether a value, or a combination of values, should be modelled as a single value object.

    Take the example of the "address": first name, insertion, last name, email, street, number, postal code, town.

    Is this eligible for a single value object, should they be all separate objects, or may they be grouped into a few value objects? How to decide?

    What about the following idea?

    Model a concept as a value object if:

    A the class of the value object restricts the type
    B group attributes as much as possible
    C no part of the concept will ever change on its own

    Add. A: There is no point in creating value objects for a concept that allows 'all integer values'; but even if the restriction is just that the concept should contain only positive integer values, there is good cause for a value object.

    The value objects adds the validation and ensures that the value falls within the range of the type.

    Add. B: It is useful to group attributes that "go together". You need to pass around less variables if you work with bigger objects. You may add restrictions that apply to several attributes combined. But, see C!

    Add. C: If the e-mail may change while the street stays the same, it is better to separate the two concepts. The insertion and the last name may be combined, because when the last name changes, it is incidental whether the insertion stays the same or not. The same holds for street, number, postal code, and town. In most domains these may be combined into a single value object, since these attributes move together. Once one attribute changes, the whole value changes. Persons may change their last name independently of their first name, but it is unlikely to be of interest to your domain. So first name, insertion, and last name may be combined.

    Add. C: This is the identity criterion, in an operational form, isn't it?

  4. Freek LijtenFreek Lijten Wrote on July 23, 2015 at 9:24:15 AM

    Hey Patrick,

    That does sound like a sensible abstraction of the decision making process concerning what should be a value object.

    I think it would be really interesting to start out with everything as a value object, even that one example you mentioned where a property may hold all integer values. Then if you've done nothing with that value object, not even a typehint, after some time you could relegate the value object back to being a poor primitive :)

  5. Smithg475Smithg475 Wrote on August 26, 2018 at 3:36:03 PM

    If you are going for best contents like myself, simply go to see this site all ekagadgkfgcbeddc

  6. Payday onlinePayday online Wrote on December 24, 2019 at 8:43:46 PM

    Great post. I was checking constantly this blog and I am impressed!

    Very useful info particularly the last part :) I care for such info much.
    I was seeking this particular info for a very long time.

    Thank you and good luck.

Leave a comment!

Italic and bold

*This is italic*, and _so is this_.
**This is bold**, and __so is this__.

Links

This is a link to [Procurios](http://www.procurios.nl).

Lists

A bulleted list can be made with:
- Minus-signs,
+ Add-signs,
* Or an asterisk.

A numbered list can be made with:
1. List item number 1.
2. List item number 2.

Quote

The text below creates a quote:
> This is the first line.
> This is the second line.

Code

A text block with code can be created. Prefix a line with four spaces and a code-block will be made.