Value Objects explained

By Vladimir Khorikov

I’ve already written about base entity class. Today, I’d like to continue with Value Object base class I use in my projects. Also, I’ll share some best practices regarding Value Objects implementation.

Value Objects: what is it?

“An object that represents a descriptive aspect of the domain with no conceptual identity is called a Value Object. Value Objects are instantiated to represent elements of the design that we care about only for what they are, not who or which they are.” [Eric Evans]

In other words, value objects don’t have their own identity. That is, we don’t care if a value object is the same physical object we had before or another one with the same set of properties. Value Objects are completely interchangeable.

For example, a dime coin would most likely represent a value object. It doesn’t matter what exact piece of metal you have, they all are just 10 cent coins. On the other hand, you may build a system which responsibility is to track every coin produced by a mint. In this case, you do care about which coin a person has because all of them have a unique identity.

Consequently, whether a class is a value object is dictated by your domain and use cases.

Attributes of Value Objects

Let’s specify attributes pertain to Value Objects.

  • No identity. A corollary of value objects’ identity-less nature is, obviously, not having an Id property. Unlike entities, value objects should be compared by value, not by identity field.
  • Immutability. As any value object can be replaced by another value object with the same property set, it’s a good idea to make them immutable to simplify working with them, especially in multithread scenarios. Instead of changing an existing value object, just create a new one.
  • Lifetime shortening. It’s another corollary of the value objects’ identity-less nature. They can’t exist without a parent entity owning them. In other words, there always must be a composition relationship between a Value Object class and an Entity class. Without it, value objects don’t make any sense.
  • Lifetime shortening leads to another consequence: Value Objects should not have separate tables in database. This one is an attribute programmers find the most controversial.

Developers, especially if they have wide experience with relational databases, tend to store Value Objects in separate tables (or, in case of NoSQL databases, in separate collections). Situation gets worse if there are more than one Entity class owning a Value Object.

For example, both Company and User entities might have a property referring to Address value object. The very first impulse could be extracting the fields concerning Address from Company and User tables to a separate Address table and storing references to it instead. I consider this approach as a bad practice. Not only does it make composition relationship more complex as you have to maintain consistency of two tables instead of one, but also gives developers a false assumption about the Address’s nature. As the Address table must have an Id column, it’s easy to mistake it for an Entity, despite its sole purpose of being a Value Object.

Give me the code!

There’s an implementation for Value Object base class made by Jimmy Bogard I often see developers copy. In short, it allows you to extract equality logic to the base class so that you don’t have to implement it in each Value Object separately. Its Equals() and GetHashCode() methods use reflection to gather information about the fields of a type and perform comparison or object’s hash code calculation.

Although this implementation might be a good solution for a quick scaffolding, it suffers from a fundamental flaw. Equality logic implementation should be a conscious decision. Every Value Object has its own unique property set and comparison strategy. By extracting this logic to a base class, you actually say that all Value Objects are just bags of data with the same behavior, which is not true. It’s worth nothing for a Value Object to have properties that don’t take part in equality logic. It’s too easy to forget to override Equals() and GetHashCode() in such cases.

Well, what should it look like then? Here’s the code I use in my projects:

public abstract class ValueObject<T>

    where T : ValueObject<T>

{

    public override bool Equals(object obj)

    {

        var valueObject = obj as T;

 

        if (ReferenceEquals(valueObject, null))

            return false;

 

        return EqualsCore(valueObject);

    }

 

    protected abstract bool EqualsCore(T other);

 

    public override int GetHashCode()

    {

        return GetHashCodeCore();

    }

 

    protected abstract int GetHashCodeCore();

 

    public static bool operator ==(ValueObject<T> a, ValueObject<T> b)

    {

        if (ReferenceEquals(a, null) && ReferenceEquals(b, null))

            return true;

 

        if (ReferenceEquals(a, null) || ReferenceEquals(b, null))

            return false;

 

        return a.Equals(b);

    }

 

    public static bool operator !=(ValueObject<T> a, ValueObject<T> b)

    {

        return !(a == b);

    }

}

Note that there’s no Id property because, as discussed earlier, Value Objects don’t have their own identity. Also, you might notice that the class doesn’t implement IEquatable<> interface. Instead, EqualsCore() is introduced. With IEquatable, you will have to write null-checking code both in Equals(object obj) and Equals(T obj) methods. Moreover, as Equals(T obj) is made abstract, you will have to copy null checks to all of the ValueObject’s subclasses. By making EqualsCore protected, you can get rid of such checks; all you should do is extract them to the Equals method of your base class.

Let’s take a look at how Address value object could be implemented:

public class Address : ValueObject<Address>

{

    public virtual string Street { get; protected set; }

    public virtual int ZipCode { get; protected set; }

    public virtual string Comment { get; protected set; }

 

    public Address(string street, int zipCode, string comment)

    {

        Contracts.EnsureNotNull(street);

 

        Street = street;

        ZipCode = zipCode;

        Comment = comment;

    }

 

    protected override bool EqualsCore(Address other)

    {

        return Street == other.Street && ZipCode == other.ZipCode;

    }

 

    protected override int GetHashCodeCore()

    {

        return (ZipCode.GetHashCode() * 397) ^ Street.GetHashCode();

    }

}

As you can see, Comment property doesn’t participate in EqualsCore() and GetHashCodeCore() methods because it’s just a user-created note; it can’t affect equality of addresses.

Also, note that properties are made read-only to comply with immutability requirement.

Value Objects and .NET value types

Strictly speaking, there’s no relation between Value Objects and .NET value types because the first is a design concept and the latter is a technical implementation detail.

However, there are a lot of similarity in these notions. Structs in .NET are inherently immutable because they are always passed by value. Also, they are much cheaper than reference types in terms of system resources. Look at DateTime struct from the BCL. It has a clear Value Object semantics: it is immutable and doesn’t have any identity fields.

In theory, you could use .NET value types as Value Objects. However, I wouldn’t recommend it. First of all, structs don’t support inheritance, so you will have to implement equality operators in every struct separately, which will lead to massive code duplication. Also, ORMs often don’t handle mapping to structs well. That said, I recommend you to always use classes for Value Objects.

Summary

Value Object is an important DDD concept. You should clearly show which of your domain classes is an Entity and which is a Value Object by inheriting them from Entity and ValueObject<> respectively.

LinkedInRedditTumblrBufferPocketShare




  • Anders Baumann

    Hi Vladimir.

    Thanks for an interesting article!

    I have a question about how to store a value object. You write: “Value Objects should not have separate tables in database.” In theory I agree but in practice it turns out that it might be a place where it is necessary to make a compromise. As Jimmy Bogard writes: “Value objects are possible using Complex Types in EF and Composite objects in NH, but don’t use them. There’s all sorts of weird behavior around null values, and ultimately you’re going to run into friction that your domain model is at fundamental odds with your persistence model…. If you need a true Value Object, and it’s not just an encapsulated primitive, you’re much, much better off treating it as an entity in EF and managing the visibility/mutability/navigation yourselves.” (https://lostechies.com/jimmybogard/2014/04/29/domain-modeling-with-entity-framework-scorecard/)

    What do you think?

    Thanks,
    Anders

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Anders, great question!

      Complex Types in EF is indeed a mess, I tried to use them to introduce Value Objects and I too couldn’t make it work. At the same time, NHibernate doesn’t have such problems and handles them very well. I can’t remember any single issue with it (and I usually have a lot of value objects in my code bases).

      You should definitely take into account the restrictions the underlying framework imposes, I agree with Jimmy Bogard on that. So if you use Entity Framework as your primary ORM, the practice of not having separate tables for value objects should probably be avoided.

      As a side note: if you want to adhere to DDD practices, I recommend you to consider switching from EF to NH if possible. I know NH sounds more like a dinosaur these days and doesn’t get as much attention as EF from the .NET community, but the fact is: unlike Entity Framework, Hibernate was developed to help developers adhere to the best practices (DDD practices included) and NHibernate successfully inherited its traits. I worked with both of them for many years, and I can say that it’s too hard to fight EF if you want to create an isolated and clean domain model. It imposes too many restrictions and does too little to help maintain proper separation of concerns. NHibernate is still way ahead of EF here and I don’t see this state of affairs changing in any near future (considering the new version – EF7 – will be released soon).

      • Anders Baumann

        Hi Vladimir.
        Thanks for your answer. We use NHibernate at work and I wanted to try Entity framework in a hobby project. Mostly for the learning experience.

        I agree with you about the DDD aspect. However, EF also has some advantages: Code first migrations, async methods and better LINQ support: https://lostechies.com/jimmybogard/2014/04/03/using-automapper-to-prevent-select-n1-problems/

        Not an easy choice. As always when it comes to tooling.

        Thanks,
        Anders

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Yeah, EF has its own advantages. I personally think async methods is the only one that is notable comparing to NH. Regarding the code first migrations, I think Fluent Migrator is a good analogue this feature.

  • Luke

    Can you elaborate on your decision to not include the Comment property in the EqualsCore() and GetHashCodeCore() methods please? I’m very new to all this and don’t get why Comment isn’t included. Great blog by the way.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      The decision of whether or not to include a field into the equality operations depends on the domain model. Here, I wanted to give an example of a situation where a field can be omitted: a comment in this case doesn’t contribute to the value object’s semantics, it’s just an arbitrary field set up by the user. Two addresses of the same Street and ZipCode should be considered the same even if the comments attached to them differ.

      I leave aside the question why the Comment field was introduced to the Address value object in the first place, I just couldn’t come up with a better example. Hope it conveys the overall idea, though. That is we shouldn’t automatically include all fields of a value object in its comparison operations at all times (although, that is what we will end up doing in most cases), we need to approach this task thoughtfully.

      • Luke

        Nice one Vladimir; that’s helped clear that up for me.