04 Entities and Value Objects System Design Fundamentals From the Perspective of Domain Models

04 Entities and Value Objects - System Design Fundamentals from the Perspective of Domain Models #

Hello, I am Ou Chuangxin. Today we will learn about two important concepts in DDD tactical design: Entities and Value Objects.

Both of these concepts are domain objects in domain models. What roles do they play in domain models, and how can we map them to code and data models during tactical design? These are the key questions we will focus on in this lecture.

Furthermore, it is important to understand and differentiate the forms of entities and value objects at different stages during the transition from strategic design to tactical design. After all, as the stages change, their forms will also change, which is closely related to our design and code implementation.

Next, we will take a closer look at these questions regarding entities and value objects in order to find some answers.

Entities #

Let’s first take a look at what entities are.

In DDD, there is a class of objects that possess a unique identifier that remains consistent throughout various state changes. For these objects, what matters is not their attributes, but rather their continuity and identity, which can span beyond the lifespan of the software. We call these objects entities. Don’t understand? No worries! Please keep reading.

1. The Business Form of Entities #

In different design processes within DDD, the form of entities can differ. In strategic design, entities are important objects in the domain model. Entities in the domain model serve as carriers for multiple attributes, operations, or behaviors. During event storming, we can identify the business entities that generate these behaviors based on commands, operations, or events, and then cluster multiple entities and value objects that have high dependency and close business association according to certain business rules to form an aggregate. You can think of entities and value objects as the fundamental units that make up the domain model.

2. The Code Form of Entities #

In the code model, the representation of entities is through entity classes, which contain the attributes and methods of the entities. Through these methods, the entity’s business logic is implemented. In DDD, these entity classes usually adopt the rich model approach, where all the business logic related to the entity is implemented within the entity class’s methods, while domain logic that spans across multiple entities is implemented in domain services.

3. The Runtime Form of Entities #

Entities exist in the form of domain objects (DO), and each entity object has a unique ID. We can modify an entity object multiple times, and the modified data may be very different from the original data. However, because they have the same ID, they still represent the same entity. For example, a product is an entity in the product context, identified by a unique product ID. Regardless of how the data of this product changes, the product’s ID remains constant, and it always represents the same product.

4. The Database Form of Entities #

Unlike the traditional approach of prioritizing data model design, DDD first constructs the domain model, builds entity objects and behaviors based on actual business scenarios, and then maps the entity objects to data persistence objects.

When mapping the domain model to the data model, an entity may correspond to 0, 1, or multiple database persistence objects. In most cases, an entity is one-to-one with a persistence object. In some scenarios, there are entities that are only transient runtime entities stored in static memory and do not require persistence. For example, a discount entity generated based on multiple price configuration data.

In more complex scenarios, there can be one-to-many or many-to-one relationships between entities and persistence objects. For instance, the user and role persistence objects can generate a permission entity, where one entity corresponds to two persistence objects, forming a one-to-many relationship. Another example is when, in order to avoid joining tables and improve system performance, customer information and account information are stored in the same database table. The customer and account entities can be generated from the same persistence object as needed, forming a many-to-one relationship.

Value Objects #

Relative to entities, value objects are more abstract. Let’s explain the concept with examples.

First, let’s take a look at the definition of value objects in the book “Implementing Domain-Driven Design”: An object identified by its attribute values, it combines multiple related attributes into one conceptual whole. In Domain-Driven Design (DDD), value objects are used to describe specific aspects of the domain, and they are objects without identifiers.

In other words, a value object describes something in the domain that is immutable. It combines different related attributes into one conceptual whole. When measurements and descriptions change, they can be replaced with another value object. It can be compared for equality with other value objects without causing side effects on collaborating objects. Examples of this will be discussed later when talking about the “runtime form of value objects”.

If you find the above two paragraphs difficult to understand, let’s “translate” them into simpler language to make the definition clearer.

In simple terms, a value object is essentially a collection. What does this collection contain? Several attributes used for descriptive purposes, with a concept of the whole and no modifiability. What is the significance of this collection? In the process of domain modeling, value objects ensure the clarity of attribute classification and the integrity of concepts, avoiding fragmented attributes.

Here is a simple example. Take a look at the following diagram:

img

The person entity originally includes attributes such as name, age, gender, and the province, city, county, and street where the person is located. Isn’t it fragmented to display the address-related attributes like this? Now, we can extract the “province, city, county, and street attributes” and form an “address attribute collection”, which becomes a value object.

1. Business Form of Value Objects #

Value objects are fundamental objects in DDD domain models. Like entities, they are constructed from domain models that originate from event storms, and they contain several attributes. Together with entities, they form aggregates.

Let’s compare them with entities to understand the business form of value objects better. Essentially, entities are tangible business objects that can be seen and touched, and they have business attributes, behavior, and logic. On the other hand, value objects are just collections of several attributes and mostly do not contain business logic, with only data initialization operations and limited non-data-modifying behaviors. Although the attribute set of a value object is physically separated, from a logical perspective, it is still part of the entity’s attributes and is used to describe the characteristics of the entity.

Within value objects, there are also shared standard types of value objects, each with its own bounded context and persistence objects. Shared data class microservices, such as data dictionaries, can be created for them.

2. Code Form of Value Objects #

Value objects have two forms in code. If the value object has a single attribute, it is directly defined as an attribute of the entity class. If the value object is a collection of attributes, it is designed as a class that collects multiple attributes with the concept of the whole. This type of value object does not have an ID and is referenced by the entity as a whole.

Take a look at the following code. The “person” entity has value objects with several single attributes, such as ID, name, etc. It also includes value objects with multiple attributes, such as the address.

img

3. Runtime Form of Value Objects #

The DO (Data Object) of an instantiated entity has rich business attributes and behavior. On the other hand, the objects instantiated from value objects are relatively simple and unexciting. Apart from data initialization and complete replacement, there are few other business behaviors.

If the value object is embedded in the entity, there are two different data formats or ways to do it: attribute embedding and serialization of large objects.

Entities that reference value objects with single attributes or value objects with only one record can be embedded using attribute embedding. Entities that reference value objects with one or more records can use serialization of large objects. For example, a person entity can have multiple contact addresses, and the serialized addresses can be embedded in the person’s address attribute. Value objects cannot be modified after they are created; they can only be replaced with another value object as a whole. If you are not familiar with these two approaches, you can take a look at the examples below.

Case 1: The person entity object formed by embedding attributes, the address value object is directly embedded in the person entity as an attribute value.

img

Case 2: The person entity object formed by serializing large objects, the address value object is serialized into a large JSON object and then embedded in the person entity.

img

4. Database Representation of Value Objects #

The introduction of value objects in DDD aims to shift the focus from “data modeling” to “domain modeling” and reduce the number of database tables and their complex dependencies, thereby simplifying database design and improving database performance.

How can we understand the use of value objects to simplify database design?

Traditional data modeling is mostly based on database normalization. Each database table corresponds to an entity, and the attribute values of each entity are stored in separate columns. A main entity table may have multiple sub-entity tables. Value objects simplify the design in terms of database persistence. Their database design mostly deviates from database normalization. The attribute values of value objects and entity objects are stored in the same database entity table.

For example, based on the scenario of the person and address mentioned above, there are usually two solutions for entity and data model design: the first one is to put all attributes of the address value object into the person entity table, creating a person entity and a person data table; the second one is to create separate person and address entities, as well as separate person and address tables.

The first solution compromises the business meaning and conceptual integrity of the address, while the second solution adds unnecessary entities and tables, which increases the complexity of database design.

So how should we design it to make the business meaning clear without making the database complex?

We can integrate the advantages of these two solutions and avoid their shortcomings. In domain modeling, we can treat the address as a value object and the person as an entity, preserving the business meaning and conceptual integrity of the address. In database modeling, we can embed the attribute values of the address into the person entity database table and only create a person database table. This way, we can take into account both the business meaning and expression and avoid the complexity of the database design.

This is how value objects simplify database design. In summary, when it comes to domain modeling, we can design certain objects as value objects, preserving the business meaning of the objects while reducing the number of entities. In terms of database modeling, we can embed value objects into entities, reduce the number of entity tables, and simplify the database design.

In addition, some DDD experts believe that to leverage the power of objects, we should prioritize domain modeling and weaken the role of the database, regarding it only as a storage repository for data. Even if it violates the principles of database design, it is not a big deal as long as the business can run smoothly.

5. Advantages and Limitations of Value Objects #

Value objects are a double-edged sword. Their advantage is that they can simplify database design and improve database performance. However, if used improperly, their advantage can quickly turn into a disadvantage. “Know thyself, know thy enemy, a thousand battles, a thousand victories.” You need to understand the scenarios where value objects are truly suitable.

By using the method of serializing large objects, value objects simplify database design, reduce the number of entity tables, and provide a simple and clear representation of business concepts. Although this design approach reduces the complexity of database design, it cannot meet the requirement for quick queries based on value objects, making it difficult to search for value object attribute values.

By using the method of attribute embedding, value objects enhance database performance. However, if an entity references too many value objects, it will accumulate a bunch of attributes lacking conceptual integrity, causing the value objects to lose their business meaning and become inconvenient to operate.

Therefore, you can consider these advantages and limitations in combination with your business scenario. If all these limitations can be avoided in your business scenario, then feel free to confidently use value objects.

Relationship between Entities and Value Objects #

Entities and Value Objects are the most fundamental objects in the underlying architecture of microservices, working together to implement the core domain logic of entities.

In certain scenarios, Value Objects and Entities can be used interchangeably, and it can be difficult for many DDD (Domain-Driven Design) experts to determine whether a domain object should be designed as an Entity or a Value Object in these scenarios. It can be said that Value Objects have great value in certain scenarios, but not all scenarios are suitable for them. You should choose the most suitable method based on your team’s design and development practices, as well as the advantages and limitations mentioned above.

Regarding Value Objects, I would like to add a few more points. In fact, there is an important reason for introducing Value Objects in DDD, which is whether to prioritize domain modeling or data modeling.

DDD advocates starting from the domain model design rather than designing the data model first. As mentioned earlier, traditional data modeling often involves one table corresponding to one entity and one main table associating with multiple sub-tables. When there are too many entity tables, it is easy to get trapped in endlessly complex database designs, and the domain model can easily be hijacked by the data model. It can be said that the emergence of Value Objects complements Entities to some extent.

Let’s continue with the previous diagram as an example:

img

In the domain model, Person is an Entity and Address is a Value Object, which is referenced by the Person entity. In the data model design, the Address Value Object can be embedded as a whole attribute set within the Person entity, forming the data model shown in the above diagram. Alternatively, it can be included in the person’s address attribute as a serialized large object, as shown in the previous table.

From this example, we can see that the same object can be designed differently in different scenarios. In some scenarios, an address may be referenced by an entity, serving only the purpose of describing the entity, and its value can only be replaced as a whole. In this case, you can design the address as a Value Object, such as a shipping address. However, in some business scenarios, an address may be frequently modified and is treated as an independent object. In this case, it should be designed as an Entity, such as maintaining address information in administrative divisions.

Summary #

Today we mainly learned about the forms of entities and value objects in different stages of DDD design, as well as the design methods that they undergo in the process of evolving from strategic design to tactical design.

This process is the process of grounding the business model into the system model, which is quite complex and tests your design abilities. Many times, we need to combine our own business scenarios to choose the appropriate methods for microservice design. It is important to note that we do not avoid traditional design methods, as what is suitable for oneself is the best. I hope you can fully understand the concepts and applications of entities and value objects, reuse the knowledge you have learned, and ultimately incorporate DDD design methods suitable for your own business into the architecture system to achieve successful implementation.