(CodeScholars.gov.tw) (Why To Decouple) : Analysis of Micropolymerization — The Source of Events (CodeDocument.com)

Aggregation is a relatively complex concept in DDD (Domain-driven design). As an important tool in DDD tactical design, it is necessary to know it well.

Aggregate refers to a group of closely related classes that form a bounded organization, with objects outside the bounded organization interacting only with the Aggregate Root:

Aggregation is often confused with generic collection. The difference is that aggregation is relative to the domain model, whereas collection is a broad concept. So specifically, what are the classes inside the aggregation besides the root? This article describes several important components (classes) that are common in an event traceability architecture.

entity

Entities are modeling tools for individual things, and each entity has a unique identifier, such as ID, UUID, Username, and so on. In most cases, an entity is mutable, its state changing over time.

Entities are easy to understand, and if we use DDD to analyze ORM business, models in ORM can be understood as entities. Each piece of data in the database has its own ID (unique identifier), and the content of each piece of data is variable.

Modeling users with entities:

class User extends Model
{
    private int $id;
​
    
    public function __construct(int $id)
    {
        $this->id = $id;
    }
​
​
    public function changePassword(string $password)
    {
        // domain code
    }
​
}
​
​
$user = new User(1);
$user->changePassword();
​
Copy the code

The value object

A value object is a model used in a domain to describe, quantify, or measure entities. Unlike entities, value objects do not have unique identifiers, and two equivalent value objects can be replaced. Value objects have Immutability. Once created, the properties of a value object are fixed and cannot be changed.

Value objects are a powerful but often overlooked modeling tool. Using value object modeling can greatly simplify our code. Let’s examine several properties of value objects.

None identifier

Value objects must not have identifiers such as ID, UUID, etc.

invariance

After a value object is initialized, its value cannot be changed. We need to be careful when modeling value objects that we should not give them the ability to change their internal properties. If a method needs to be mutated, it must create an entirely new value object (see Money::add() below).

class Money
{
    private int $amountInCent;
​
    private string $currency;
​
    public function __construct(int $amountInCent, string $currency)
    {
        $this->amountInCent = $amountInCent;
        $this->currency = $currency;
    }
​
    public function getAmountInCent(): int
    {
        return $this->amountInCent;
    }
​
    public function getCurrency(): string
    {
        return $this->currency;
    }
​
    
    public function add(Money $money): Money
    {
        if ($this->currency !== $this->getCurrency()) {
            throw new \Exception('You can not add two different currency');
        }
        
        return new Money (
            $this->amountInCent + $money->getAmountInCent(),
            $this->currency
        );
    }
}
Copy the code
replaceability

The immutability of value objects is the basis of their replaceability. If two value objects have equal values, we can safely replace two value objects. We can understand this concept in this way: if A has a 10 RMB note and B also has a 10 RMB note, they can make an equal exchange without any dispute of interest.

Many models in the domain can be modeled using value objects, and its features give us a secure, flexible environment to manage our code. For example, $password from the previous section can be done using a value object.

class Password
{
    private string $value;
​
    public function __construct(string $value)
    {
        $this->guard($value);
        $this-> value = $value;
    }
​
    public function toString()
    {
          return $this->value;
    }   
    
    private function guard($value)
    {
       if (empty($value)) {
           throw new /Exception('invalid password value');
       }
    }
}
​
​
$user = new User(1);
$password = new Password($passwordStr);
$user->changePassword($password);
​
Copy the code

A successful initialization of $password must be valid because we are defending it during initialization. Value objects provide us with a safe model, and we don’t have to worry about whether $Password meets business requirements for the rest of the code.

Aggregate root

The essence of an aggregate root is an entity, or an aggregate root is a special entity. The particularity of the aggregate root lies in its position in the aggregate. It is the unique interface of the aggregate. If we think of the aggregate as a household register, then the aggregate root is like the head of the household, through which any operation of the household register must go.

Field events

Domain events are business events within the domain that are relevant to the business, independent of infrastructure, code framework, so domain events should not be extremely broad framework events such as EmailSent, RecordUpdated, etc.

Domain events are generated in the aggregation root and then stored for persistence. Domain event persistence is the last step to ensure that all domain events are correct. If there are any exceptions, domain events are not saved incorrectly.

conclusion

In an event-traceability architecture, an aggregation must consist of an aggregation root and one or more of the above parts.

(CodeCode.com) If you are also interested in TDD, DDD, and clean code, welcome to Our website (Why Couples) to explore software development.