DDD Building Blocks – Value Objects

Value objects are one of the foundational building blocks of Domain-Driven Design. They allow modelling concepts of the Ubiquitous Language that describe, measure or quantify other things in the domain.

It is crucial to understand their characteristics and make more use of them whenever possible instead of trying to model every concept as an Entity or worse, having an Anemic Domain Model where logic related to a value leaks and spreads around services or client code. Values help separating concerns and they are easier to implement, test and maintain.

Examples of Value Objects in a domain could be colour, money, address, e-mail, coordinate, etc. Note that a concept can be an Entity in one domain model and a Value Object in other.

Value Object Characteristics

– Inmutable Conceptual Whole
– Describes, Measures or Quantifies an Entity
– Does not have a unique identity
– Structural equality
– Replaceability
– Side-Effect-Free Behaviour

Implementing Value Objects

Constructors

Value objects are inmutable, do not implement setter methods for its properties, instead provide a constructor with all parameters necessary to initialize its intrinsic state. Parameters may be other objects used to derive internal properties on the new Value.

public class Money {
    private BigDecimal amount;
    private String currency;

    public Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public String getCurrency() {
        return currency;
    }
...

You can find useful, especially for testing immutability, to provide a copy constructor.

    public Money(Money money) {
        this.amount = money.amount;
        this.currency = money.currency;
    }

Use Guard Clauses in the constructor to ensure that the parameters passed are not only valid individually also as a whole initialize a valid Value.

public class FullName {
    private String firstName;
    private String lastName;

    public FullName(String firstName, String lastName) {
        if (firstName == null || lastName == null) {
            throw new IllegalArgumentException("First and last name are required.");
        }

        this.firstName = firstName;
        this.lastName = lastName;
    }
...

Self-encapsulation/delegation

Value objects must not expose setter methods, but internally, we may use and delegate to them to simplify constructors.

For example, we can refactor next constructor

public class EmailAddress {
    private String email;

    public EmailAddress(String email) {
        if (!isValidEmail(email)) {
            throw new IllegalArgumentException("Invalid e-mail address.");
        }

        this.email = email;
    }

    public static boolean isValidEmail(String email) {
        return email != null && email.matches("[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{3}");
    }
...

to this

public class EmailAddress {
    private String email;

    public EmailAddress(String email) {
        this.setEmail(email);
    }

    private void setEmail(String email) {
        if (!isValidEmail(email)) {
            throw new IllegalArgumentException("Invalid e-mail address.");
        }

        this.email = email;
    }
...

Equals, hashCode and toString methods

Value objects have structural equality that means they should implement the equals() method and in Java also the corresponding hashCode() method. I simply use the IDE to generate them.

ValueObject Interface

I like to make explicit which classes perform the value object role in my applications making them implement a simple ValueObject interface.

/**
 * Value Object
 */
public interface ValueObject {
}
...

/**
 * Money Value Object
 */
public class Money implements ValueObject {
    private BigDecimal amount;
    private String currency;
...

Side-Effect-Free Behaviour

Apart of the common constructor and methods, value objects can hold side-effect-free methods with logic that is related to the domain concept they model.
For example for a PersonName Value Object with a first name and second name properties, we could need a fullName() method that concatenates and returns the full name.
Or for a Money we can provide a sum method that adds up two money values and returns a new one.

Implementing Value Object with Lombok annotations

An interesting approach for implementing Value Object classes in Java saving us from coding all the boilerplate required for getters, equals, hashCode methods, is to use the Project Lombok @Value annotation.

import lombok.Value;

@Value
public class FullName {
    private String firstName;
    private String lastName;

    public String fullName() {
        return firstName + " " + lastName;
    }
}

ddd_value_object_lombok_value

Persisting Value Objects

Model the persistence store in the way necessary to deal with the storage of the object, but don’t let that influence the way your team conceptualizes the Value property in the domain model. (Vaughn Vernon, IDDD)

Value Objects are persisted along with the Entity that contains them. We should consider 1-to-1 and 1-to-Many relationships and have in mind that a Value Object can be complex formed by a compound of other Values.

ORM, Single Value Object embedded in Entity table

The simplest case is to persist a Value to Entity relationship. One way to achieve this in Java is using JPA Embedable classes.
The single value object annotated as @Embeddable is denormalized (its fields are inlined) into its parent entity row.

@Embeddable
public class Money implements ValueObject {
    private BigDecimal amount;
    private String currency;

    private Money() {} // Hibernate requires that Entities or Embeddable classes implement a default constructor. Remember to keep it private to hide it from client code.
...
}

@Entity
public class Product {
    @Embedded
    private Money price;
...
}

ORM, Multiple Value Objects persisted in its own table

An example could be a Customer entity that has a list of Phone Value Objects.

Implemented using JPA ElementCollection the phones will be stored in its own table.

@Entity
public class Customer {
  ...
  @ElementCollection
  @CollectionTable(
        name="PHONE",
        joinColumns=@JoinColumn(name="OWNER_ID")
  )
  private List<Phone> phones;
  ...
}

Use a Document-Oriented Database

A different approach to simplifying persistence and preventing our domain model for being influenced by data modelling and ORMs is to use a Document-Oriented Database. Aggregates can easily be persisted along with its Entities and Value Objects in a document.

References:

– Domain-Driven Design, Eric Evans
– Implementing Domain-Driven Design, Vaughn Vernon
– ValueObject, Martin fowler
https://martinfowler.com/bliki/ValueObject.html
– AnemicDomainModel, Martin fowler
https://martinfowler.com/bliki/AnemicDomainModel.html
– SelfEncapsulation, Martin fowler
https://www.martinfowler.com/bliki/SelfEncapsulation.html
– Persisting Value Objects, Paul Rayner
http://thepaulrayner.com/persisting-value-objects/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s