June Architect: Domain Model Structure - Part 5: Loading Value Objects into Memory

In my last article, we talked about Value Objects, domain model elements with no conceptual identity. We said that Value Objects represent descriptive aspects of the domain and are fully defined by their state. This month, we will review the options for loading Value Objects into memory.

Potluck Principle of getting Value Objects

The Potluck Principle states that if you need to obtain a Value Object in your code, you have the following three options:

  1. You may be able to create the Value Object yourself
  2. You may be able to ask another object to give the Value Object to you
  3. You may be able to reconstitute the Value Object from a previously stored state

Option 1: Create Value Objects yourself

You can create a Value Object by calling it's constructor or factory. This is a very simple method but there is a catch: since Value Object are immutable, you need to know all their required attributes at the moment of construction.

Example: Creating an instance of the Address class based on a submitted HTML form.

Option 2: Ask other objects to give Value Objects to you

If you need a Value Object in your code, who could you ask for it? Since Value Objects are often descriptors, you may be able to query objects their describe (usually Entities or other Value Objects).

Example: asking Person Entity for the Person's Age or asking Email Address Value Object for it's Domain.

Another popular way is to obtain a Value Object as a result of an operation call closed under the Value Object interface.

Example: (new Money($10)).Multiply(2) results in new Money($20) or Color.Blue.Mix(Color.Yellow) returns Color.Green.

Option 3: Recreating a Value Object from a previously stored state

As discussed in my previous posts, Value Objects are tracked only as part of Entities they describe, in which case they are loaded into memory using Option 2. Value Objects are not recreated from previously stored states.

However, there is a situation when Value Objects need to be created independently. For example, it is a fairly common requirement to display the list of Value Objects in a drop-down list.

Example: User submits a new Purchase Order. As part of the entry screen, the user chooses Billing and Shipping Address for the new Purchase Order. All 50 States are selectable on the Billing Address form, but only 48 States are selectable on the Shipping Address form.

How shall we populate drop-down lists of 48 and 50 States for the New Purchase Order screen?

I have heard software designers making arguments towards promoting State to an Entity. Then, State Repository would be responsible for retrieving the right lists of States to display in each situation. I disagree with such design. It introduces a responsibility of managing States into the domain model, which can be easily avoided if we keep States as Value Objects.

Another important point against introducing the IStateRepository interface is that business rules of whether to display a particular State in a drop-down or not do not belong to the State class. For example, the company could introduce a new Product, which could be shipped to all 50 States.

My preference is to assign the responsibility of knowing about Value Object lists to aggregate repositories. In our example, IPurchaseOrderRepository would have FindStatesForShipping and FindStatesForBilling methods.

Happy coding! To be continued...

March Architect: Domain Model Structure - Part 4: Value Objects

In the Part 2 and Part 3 of the Domain Model Structure series, we continued our discussion around how to organize classes inside your domain model. We defined Entities, looked at their relationships, and reviewed options for loading them into memory. This month, we will take a look at Value Objects.

Discovering Value Objects

Value Objects are domain model elements with no conceptual identity. They represent descriptive aspects of the domain and are fully defined by their state. Their behavior depends on what they are, not who they are. If they need to be tracked, they should be tracked with the elements they describe. Thus, they do not need an identity of their own.

We prefer to keep Value Objects immutable, i.e. changeable by full replacement only. Immutable Value Objects are safe to share (which increases performance), and easy to understand (which allows you to build complex behaviors). Let me give you an example based on a classical OO problem:

Assume you have two buckets of paint: b1 and b2. The first bucket b1 contains 1 gallon of yellow paint. The second bucket b2 contains 1 gallon of blue paint. Without looking into the code, could you answer the following questions about the results of the operation b1.Add(b2)?:

  1. What will be returned by the Add method? Is it 2 gallons of green paint or nothing?
  2. What will be in the the first bucket b1? Is it 2 gallons of green paint or 1 gallon of yellow paint?
  3. What will be in the second bucket b2? Is it 1 gallon of blue paint or nothing?

If you notice, we do not have a requirement to track buckets of paint. Thus, I will assume that Bucket is a Value Object and should be immutable. Since both buckets are immutable, they will contain their original values of 1 gallon of paint each and the result of the Add operation will be 2 gallons of green. With no convention in place, it would be impossible to answer these questions without checking the code or better yet unit tests first.

You domain has many Value Objects, a lot more than Entities. If you are having troubles seeing them in your system, take a closer look at the Entities. How are they being described? What are their attributes and properties? How are they being searched for or ordered by? The chances are you will be talking about Value Objects.

Examples: Address, DayPoint, Money, Range, SSN, etc.

Domain Model Structure

Value Objects along with Entities are main elements of the domain model. Many of them are small simple classes that will be widely used in your application. Place them together in a sub-folder under the Domain Model root. We name this folder "Capability":

Domain Model Structure - Capability folder

You are likely to have a number of very complex Value Objects as well. I will try to discuss some of them in my future articles.

Summary and Additional Tips

  1. Never define an identity for a Value Object.
  2. Consider overriding equality operators to match Value Objects using object attributes rather than object references.
  3. Keep Value Objects immutable.
  4. Place Value Objects used across many applications into a dedicated Domain Kernel library.
  5. If you are interested in creating a simple base Value Object class, you can start with the one listed below:

    Domain Model Structure - Value Object Template

Happy coding! To be continued...

Welcome to ModelBlog

Thank you for visiting ModelBlog. We hope the time you spend with us will be both entertaining and worth your while. Have fun!