eShopOnWeb Architecture (2/16) – uses Value Objects to model immutable domain concepts

Value Objects (VO) are a core part of DDD. A Value Object is an immutable type that is distinguishable only by the state of its properties, it doesn’t have the concept of identity.

Value Objects can better represent some domain concepts compared to entities

IMHO the main advantage of using Value Objects is that they can better represent and model certain real world concepts compared to regular entities with identities.

For example if we are dealing with money our domain might not care about the fact two $5 notes are different, for our business $5 is $5. If on the other hand we are some central bank or the US Fed and want to track the flow of currency in an economy then $5 with the serial number ABC is considered different than the $5 with the serial number XYZ.

Both domains above deal with money but how its handled and compared in each one is different. Value Objects give us the extra level of granularity needed to more correctly model this difference. 

Always valid after creation

Another big benefit from using Value Objects comes from the fact they are immutable, this means once we validate them on creation we never have to worry about validation again. This can simplify our code base significantly.

We can see in eShopOnWeb that Address is a value object, after creation it is not possible to change its properties

To keep things simple in this case we don’t have a full Value Object implementation as we don’t have logic for comparing two Value Objects together. This can be done a number of ways but a typical implementation is to use an abstract base class along with an overridden method in our derived Value Type which will return the list of properties we need to include when comparing two Value Objects.

Using Records for Value Objects in C#?

Records were introduced in C#9 and give us built in immutability and comparison checks. Can we use them to model Value Objects? In many cases yes, but beware there are some limitations when using records over classes to model Value Objects as discussed by Vladimir Khorikov.

What does your typical Value Object implementation look like? Do you mostly use Records or Classes?

eShopOnWeb Architecture (1/16) – uses marker interfaces to communicate intent and enforce design constraints

eShopOnWeb has an interface called IAggregateRoot which has no methods or properties… what’s that about?

Well empty interfaces like this are often referred to as ‘marker’ interfaces and are used to flag classes as being of some kind of type.

We can use them as an extra contextual clue to communicate intent to other developers and to enforce design constraints. For example we can see below that the only classes allowed to implement the IRepository interface are those of type IAggregateRoot.

Click on the image for a larger view in a new tab…

Are marker interfaces useful?
Are they really needed?

IMHO it’s vital when we are working on a platform, open source software, a framework, a library etc.. when we never meet the devs who are consuming our code to provide a steer and guide these external developers as much as possible. In this case marker interfaces can definitely be a useful addition to the overall architecture.

On the other hand when we are working in a closed loop with a bunch of developers we talk to everyday marker interfaces might be a bit superfluous. I think there’s probably other ways to make sure a developer doesn’t create an repository for OrderLine.cs (for example) as its not an aggregate root… eg.. code reviews, PRs etc.

… And remember there’s nothing to stop a developer having OrderLine.cs implement IAggregateRoot to ‘bypass’ design constraints.. so ultimately it still all comes down to developers not making mistakes.

Microsoft recommends against them

Note… Microsoft actually recommends against them on their Interface Design page and suggests using attributes instead…

… unfortunately its not possible to enforce constraints against attributes as easily as it is against types.