Value Objects as Embedded Entities
Value Objects as Embedded Entities
This post discusses the value object pattern, and the factory pattern which are tactical patterns in the domain driven design DDD approach.
Value objects represent typed values, that have no conceptual identity in your domain. They can hel you write better code that is less error-prone, more performant and more expressive.
Value objects define the second kind of domain objects besides entities. Their main characteristic is immutability:
Attributes of a value object never change.
A second characteristic is they do not have external identifiers. Unlike an entity two value objects with the exact same properties are considered equal.
A third one is they should be self-validating. A value object shall verify the validity of its attributes when being created. If any of its attributes are invalid, the object should not be created and an error or exception should be raised.
Value Objects do have attributes and methods as entities. Attributes of value objects are immutable therefore methods of value objects can only be queries without side effects. Operations never command a change to the internal state of a value object. We can pass value objects to clients without worrying they change them.
Many objects can be modeled as value objects instead of entities because they are defined through their attributes. These objects measure, quantify or describe things in the domain model. Because they are so easy to handle we should model domain abstractions as value objects as often as possible.
Addresses, Phone Numbers, Email Addresses
Some value objects are part of any commercial application domain. Postal addresses, phone numbers and email addresses are canonical value objects. Other candidates are bank account IBAN numbers, job titles, job descriptions, company legal statuses.
This means that these objects do not have an object identifier and should not be stored in a separate table if stored in a SQL database. Value objects shall be embedded objects and be part of an object such as a person.
A person is an entity. It should have an external identifier and has a postal address, multiple phone numbers, and one or more email addresses.
Check your domain model and validate these assumptions.
- Postal address, phone numbers, email addresses are value objects and have no external or internal identifiers.
- They are always owned by other value objects or more often by entities such as persons, companies, delivery forms.
- They are immutable objects.
- Business processes can replace such an object with a new instance without impeding other domain instances.
- Programmed in modern Java these value objects should be records to guaranty immutability at the language level. As a bonus you get the hashCode and equals methods for free.
Invoice lines are lines containing details in an invoice. Invoice lines are always value objects belonging to exactly one invoice.
To complicate matter, invoice lines have different types such as a regular line with a specific article, quantity, unit price and computed price. Often VAT aspects must be considered and computed for the overall invoice. An invoice line can also be a subtotal for a set of regular invoice lines.
VAT definition and computation is often a murky domain. The VAT value can be dependant of the article, the company selling it and the client buying it. Often when public administration defines a domain and associated business rules the world becomes quite complicated and ambiguous. The VAT administrative laws in Switzerland are more than 2000 pages of illegible text.
The complete definition of this business domain is not part of this article.
The following design challenges exist
- Serialization libraries such as JSON Jackson library cannot handle invoice lines with multiple Java class types. A workable approach is described and implemented with the open source component Gleam. The solution is to define selectors to instantiate the correct Java class.
- Invoices are complex objects and ideal candidates for a document oriented persistent approach. Invoices should not be stored in a relation based persistence store, meaning a SQL database. To store them in a table you have to model the various type of lines and add a technical identifier to each invoice line instance.
The factory pattern in Domain Driven Design DDD can be seen as a super pattern for the Gang of Four (GoF) creational patterns. Factories are concerned with creating new entities and value objects. They also validate the invariants for the newly created objects. We can place a factory on the entity or value object itself or on an independent object.
Factories that are declared on the same object they create are either factory methods or prototype methods. The factory method creates a completely new object from the method parameters. The prototype method uses an existing instance to derive a new object.
When the creation logic is complex or has dependencies that are not needed by the created object it is best to create a separate factory. This factory could provide multiple ways to create new instances.
Value Objects in Persistent Store
We encourage experimenting with the MicroStream approach for small projects. The effort to persist a Java object graph is very small.
You can always move to a no SQL solution when your application is successful and time is come to harden it. Another standard but cumbersome approach is to move to JPA.
Related concepts are discussed in our blog series