Domain-Driven Design: Entities, Value Objects and Services
Domain-Driven Design Chapter 5.1
This chapter focuses on connecting model and implementation. The chapter is large and it has a lot of important information that's why I decided to split it.
Patterns of Model Elements
- Entities: Something with an identity relevant to the domain. It has a state and is continuous through the system even if the state changes. (example: a transaction in a banking system)
- Value Objects: Describes an attribute or a value of something else. It has no identity or state and is often created for an operation then destroyed (example: address of the customer in a banking system)
- Services: Actions or operations that are done on client's requests. They belong to no specific object. ( example: sending an email of a transaction in a banking system)
Entities
Entities are objects that are in the core of the domain. The system needs to have the state of those objects and they need to be identified.
The implementation of entities should focus on the life cycle of the entity more than the attributes. The entity itself is important regardless of its attributes.
Across a system, entities might have different implementations in the sub-systems. However, In all implementations the objects must refer to the same entity.
Entities have an operation that gives a different value for each instance of the entity. This operation is used for identifying the instance.
The domain model defines what it means for 2 objects to be equal.
A quick way to identify an entity is to answer the question "Does the user need to know if X is the same entity as before?" or in other words "Does the user care about the identity of it?"
An example to that is having a customer object in a banking system. The customer itself is important to the User and the system must allow for the identification of different customers. The customer might fail to pay a loan or they might own a number of accounts. The identity of the customer is important to know which customer owns which accounts or which customer failed to pay.
Modeling Entities
Don't focus on the attributes, strip the object down to the most fundamental characteristics. The attributes that define the object and that are used to match the object with other objects that belong to the entity.
Add behavior that is essential to the identification of the entity and attributes that are used by that behavior.
Remove other behaviors and attributes to other objects and associate them with the entity.
An example to that is a customer object. a customer would have a unique id, a name and an address. According to the domain of banking, the customer is not identified by the address but it is identified by its id and name. Thus, the address attributes should be moved to another "Address" object.
Designing the Identity Operations
- Defining attributes must be unique. For example, the national ID of a customer.
- If there is no unique attributes, then attach a unique ID to the object. Most databases do that automatically.
- Identify what makes 2 objects the same entity.
- Identity operations can require human input if the ID does not correspond to something in the business domain.
- When an entity needs matching on two different systems whose IDs are different, a third system is used for attaching for example the national ID or the Phone number
Value Objects
- Value objects have no identity but their attributes describe something.
- If you only care about the attributes of the object but not the identity, then it is a value object
- An example to that is a marker pen. If you're coloring, you don't care which pen you use but you care about its color. So all instances of the pen that have the same color are the same and it doesn't matter which pen you're using. The pen is defined by its attributes but the pen itself has no identity.
Is an address a value object or an entity? This is an important question. The short answer to that is "It depends". It depends on the domain. If you're running a delivery service, then knowing if 2 people who made an order live in the same address is not important so it is a Value Object. However, if the system plans the delivery route then it is important to know that they have the same address so they are delivered together then it is an Entity.
The same object can be an Entity or a Value Object depending on the domain.
Designing Value Objects
- Which instance of the object we have doesn't matter as long as they have the same attributes.
Caring only about the attributes and not the identities allows for more optimization. If the value object is an electrical outlet in a home designing system, then we can either create multiple copy of the outlet or create one and refer to it a hundred times. When should we copy and when should we share?
Copying will send only a copy of the object but it means that you use more space to store redundant copies. However, sharing sends a reference to the object but it also sends a message for every change to the object so the main object changes. In short, Copying uses more space but less network overhead while sharing uses less space but more network overhead unless the object is immutable.
- Associations should not be bidirectional. If bidirectional associations are needed then consider changing the object to an entity. That's because Value Objects have no identity so having a bidirectional relationship makes no sense.
Services
Services are operations that belong to no specific object but they are important to the domain.
Not anything that has no home in an Entity or a Value Object is a Service. You must first try to place the operation in an Entity or a Value Object and not give up and make it a Service.
Services have no state and no meaning beyond their operation.
The parameters and results should be domain objects.
To keep the design clear, those operations are declared as services instead of creating an object that represents nothing in the domain.
Good Service Characteristics
- The operation is part of the domain but it is not a natural part of an Entity or a Value Object.
- The interface is defined in terms of other domain elements.
- The operation is stateless. A service can use global system info or change them but the service itself should have no state.
Service and the Isolated Domain Layer
This is a pattern focused on distinguishing domain layer services from services in other layers. Usually, a Service is something in the infrastructure layer like a mailing service and they lack any domain meaning. Services that have domain meaning are in the domain layer. But differentiating between services in the application layer and domain layer can be confusing. For example, If we have an operation that exports the transactions as excel then it should be on the application layer because the domain has no concept of file formats. However, an operation that transfers money from one account to the other should be in the domain layer because that's where the business rules reside and the action is a core part of the domain. Here is a more detailed example from the book (I made some changes to it).
A request to make a transfer from one account to another might be processed like this:
Application Layer:
- Get input request
- Ask domain layer service to do the transfer and wait for response
- Send notification through mailing service in infrastructure layer
Domain Layer:
- Check if transfer is possible according to business rules
- Make changes in account balances to transfer fund
- Return result to application layer service
Infrastructure Layer:
- Send notification email
Granularity
Making services medium-grained allows for more reusability because the service has a lot of functionalities. Having a fine-grained service can cause the application layer to have a lot of domain details so it can coordinate those services which blurs the line between application and domain layers. It is better to have medium-grained services to avoid that.
Conclusion
This is the first half of the chapter. It introduces Entities, Value Objects and Services as components of the implemented model. It explains how to differentiate between them and how to best use them to reflect the domain while achieving the system's goals.