cult3

Defining the building blocks of Domain Driven Design

Sep 15, 2014

Table of contents:

  1. What is the benefit and why is this important?
  2. The Value Object interface
  3. The Identifier interface
  4. The UUID abstract class
  5. The Entity interface
  6. The Aggregate Root interface
  7. The Has Events Trait
  8. Conclusion

An important part of the beauty of Domain Driven Design is the fact that we have a language to describe certain concepts and components within our application. Terms like Aggregate Root, Value Object and Entity have concrete meanings that describe how our applications are formed.

Whilst these terms form part of the structure of Domain Driven Design, and not our application’s domain model, it is still important to represent these concepts explicitly in the code we write.

By using the same terminology in how we describe the application, as well as how we write the code, we dispel a lot of the confusion that can arise from application development.

In today’s tutorial we’re going to look at how we can write some basic objects, interfaces and traits that can be used throughout the project.

By creating this foundational layer, we set up our application with a rich set of objects and interfaces to implement to make our domain related code more expressive.

What is the benefit and why is this important?

Before I jump into the code, I want to explain my reasoning as to why I think this is an important thing to do.

In Object Oriented Programming, we represent concepts of our application as objects. Within the scope of a Domain Driven Design project, the objects of the project fit into a number of explicitly defined types.

For example, we’ve already seen how we can encapsulate behaviour in Value Objects. Value Objects are immutable and very important when modelling a domain. On the other hand, objects in which identity is important are represented by Entities.

Value Objects and Entities have a number of characteristics that they must possess in order to meet the requirements of that object type.

For example, the equality of Value Objects is based upon the attributes of the object, whereas Entities must have a unique identifier that ensures continuity as the properties of the object change over time.

To ensure that the objects of our application meet these requirements we can define interfaces, extend abstract classes or use traits to ensure that the functionality is implemented.

This also makes our code much more readable because you can simply open up a class and see exactly what type of object it represents and what it is capable of.

There are many Open Source repositories that define these types of interfaces or Value Objects for you. Personally I think it is better to write this type of code for each project as it means the code will actually live inside of your project. It also means you don’t have to compromise with generic interfaces or lose some of the semantic meaning from your domain.

So hopefully that makes sense. In short, we can use the basic building blocks of PHP to enforce stricter adherence to the principles of Object Oriented Programming, as well as make our code more explicit and easier to use!

If any of that didn’t make sense to you, take a look at the following previous posts:

The Value Object interface

The first component I’m going to look at is for Value Objects. Value Objects are arguably one of the most important parts of Domain Driven Design as they allow you to explicitly capture behaviour and encapsulate business rules in immutable objects.

We’ve already seen examples of Value Objects a couple of weeks ago when we looked at creating Email, Username and Password objects.

One of the important attributes of a Value Object is that it should have equality with another Value Object instance if they both posses the same properties.

We will also need to recreate a Value Object from it’s native form. For example, when you return a Value Object from a database or HTTP request.

We can enforce that all Value Objects of the application implement these two characteristics by using the following ValueObject interface:

<?php namespace Cribbb\Domain;

interface ValueObject
{
    /**
     * Create a new instance from a native form
     *
     * @param mixed $native
     * @return ValueObject
     */
    public static function fromNative($native);

    /**
     * Determine equality with another Value Object
     *
     * @param ValueObject $object
     * @return bool
     */
    public function equals(ValueObject $object);
}

Each Value Object will need to implement these two methods in order to satisfy the interface contract.

We can also now type hint to ensure that the object we are working with is an instance of ValueObject.

It might be handy to also have a toString() method for saving the Value Object to the database or sending the object over the wire during an HTTP request. However instead of defining it as a required method, I will instead just implement it on the instances where it makes sense. I may add it to the ValueObject interface in the future if all of my Value Objects end up using it.

The Identifier interface

A couple of weeks ago we looked at using UUIDs instead of auto-increming ids.

For each Entity we’re going to need to create an id Value Object. However, these objects are special types of Value Objects, and so we should define a special interface to represent them.

As with regular Value Objects, we need a way to test for equality and recreate an identifier from a native form (in this case a string).

We also need to be able to generate new identifiers as we add new records to the database, and we will need to convert the object to a string for when we save to the database or send the object over the wire in an HTTP request.

To ensure each identifier class implements these methods we can use the following interface:

<?php namespace Cribbb\Domain;

interface Identifier
{
    /**
     * Generate a new Identifier
     *
     * @return Identifier
     */
    public static function generate();

    /**
     * Creates an Identifier from a string
     *
     * @param $string
     * @return Identifier
     */
    public static function fromString($string);

    /**
     * Determine equality with another Identifier
     *
     * @param Identifier $other
     * @return bool
     */
    public function equals(Identifier $other);

    /**
     * Return the Identifier as a string
     *
     * @return string
     */
    public function toString();
}

The UUID abstract class

As I’ve just mentioned, we’re going to be using UUIDs instead of auto-incrementing ids in this project. However in theory, you could use any number of methods for creating identifying objects along as they implement the Identifier interface.

In order to reduce code duplication, I will make an abstract UuidIdentifier class that can be extended by each identifier implementation. This will mean I don’t have to repeat the same boiler plate code each time I need to write a new class.

The UuidIdentifier class looks like this:

<?php namespace Cribbb\Domain;

use Rhumsaa\Uuid\Uuid;

abstract class UuidIdentifier implements Identifier
{
    /**
     * Generate a new Identifier
     *
     * @return Identifier
     */
    public static function generate()
    {
        return new static(Uuid::uuid4());
    }

    /**
     * Creates an identifier object from a string
     *
     * @param $string
     * @return Identifier
     */
    public static function fromString($string)
    {
        return new static(Uuid::fromString($string));
    }

    /**
     * Determine equality with another Value Object
     *
     * @param Identifier $other
     * @return bool
     */
    public function equals(Identifier $other)
    {
        return $this == $other;
    }

    /**
     * Return the identifier as a string
     *
     * @return string
     */
    public function toString()
    {
        return $this->value->toString();
    }

    /**
     * Return the identifier as a string
     *
     * @return string
     */
    public function __toString()
    {
        return $this->value->toString();
    }
}

As you can see, we’re able to implement all of the methods of the interface within this abstract class.

This means the identifier class can be really simple. For example, the UserId class now looks like this:

<?php namespace Cribbb\Domain\Model\Identity;

use Rhumsaa\Uuid\Uuid;
use Cribbb\Domain\Identifier;
use Cribbb\Domain\UuidIdentifier;

class UserId extends UuidIdentifier implements Identifier
{
    /**
     * @var Uuid
     */
    protected $value;

    /**
     * Create a new UserId
     *
     * @return void
     */
    public function __construct(Uuid $value)
    {
        $this->value = $value;
    }
}

The Entity interface

As I mentioned above, Entities are objects that have an identity within the application. This means the properties of the Entity can change, but the identity of the Entity will remain consistent.

This means that all Entities should have an identifier.

We can ensure that all Entities do have an identifier with the following interface:

<?php namespace Cribbb\Domain;

interface Entity
{
    /**
     * Return the Entity identifer
     *
     * @return Identifier
     */
    public function id();
}

The Aggregate Root interface

In Domain Driven Design, Aggregate Root is a very important concept. The Aggregate Root is the most important entity of a particular piece of functionality that controls how other Entities and Value Objects interact.

For example, you might have a Post Aggregate Root that controls interaction with Tag, Comment, Author and Category objects.

A Comment object does not make sense without a Post object and so the Post object controls how access to Comment objects flows.

It is therefore extremely important that we identify Aggregate Root objects because they form the backbone of our project.

Aggregate Roots should always have an identifier as they are Entity Objects. We will also be using Domain Events in a future tutorial so we need a way of recording and releasing Domain Events during the lifecycle of the Aggregate Root.

<?php namespace Cribbb\Domain;

interface AggregateRoot
{
    /**
     * Return the Aggregate Root identifer
     *
     * @return Identifier
     */
    public function id();

    /**
     * Add an event to the pending events
     *
     * @param $event
     * @return void
     */
    public function record($event);

    /**
     * Release the events
     *
     * @return array
     */
    public function release();
}

The Has Events Trait

Each Aggregate Root is going to need the implement the record() and release() methods that we have defined in the AggregateRoot interface.

The record method will accept Domain Events as they happen and store them in an array on the Aggregate Root.

At an appropriate time during the execution of the application, those events will be released to trigger actions throughout the application.

Instead of repeating this functionality on each Aggregate Root, we can instead write a trait that can be included:

<?php namespace Cribbb\Domain;

trait HasEvents
{
    /**
     * @var array
     */
    private $events;

    /**
     * Record that an event as occurred
     *
     * @param $event
     * @return void
     */
    public function record($event)
    {
        $this->events[] = $event;
    }

    /**
     * Release the pending events
     *
     * @return array
     */
    public function release()
    {
        $events = $this->events;

        $this->events = [];

        return $events;
    }
}

Now whenever we include this trait on an Aggregate Root, that object will have both the record() and release() methods.

By naming the trait HasEvents we also make our class much more readable.

Conclusion

We will likely encounter more generic objects and interfaces that we will need to implement as we continue to build out this application. For example, we might need to define Value Objects for dates and times, IPs or co-ordinates.

None of the code that we’ve written today was very complicated or built functionality for the application. But in the grand scheme of building an application, we’ve explicitly identified a number of important concepts and solidified our understanding in code.

Now whenever we need a new Value Object, Entity or Aggregate Root we can draw upon the interfaces we have already defined.

Also when we need to jump back in to an unfamiliar part of the code base, or we collaborate with someone else, our code is much more readable and understandable at first glance.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.