I’m aware that the general consensus is that Value Objects should not go into messages. But, I’m curious how this applies to Id (eg. Aggregate/Entity) classes. In Axon Trader, CreateCompanyCommand is using such value objects (ie. CompanyId, UserId). I was hoping I might get some real-world feedback on this practice. Thanks.
From the Axon Trader’s example, and other actual use case I’ve come across, using a strongly typed id is most often a good practice.
I’d helps you to overcome the accidental reuse of an id when you’re issuing commands to different aggregates.
Additionally, the framework leverages the
toString() function of the
@AggregateId annotated field to deduce what the
aggregate-identifier column in the
domain-event-entry table will contain.
By thus having a strongly typed Id, per aggregate, you could add the aggregate type to the
toString() function, thus allowing potential reuse of the aggregate identifier between different aggregate types.
Although we typically suggest against the reuse of aggregate identifiers, sometimes it’s a most from a business case perspective - having an actual Id class makes the developers live a little easier in this respect.
Due to the above, we added the CompanyId and UserId into the Axon Trader example.
That’s my two cents.
What about enums?
I’m curious about your statement about the general consensus is that Value objects should not go into messages. Where can I read more about this line of thinking? Personally, I have found that the usage of Value objects in my Event and Command messages saves a lot of data transformation logic.
If you search on ”cqrs value object message”, you should find plenty of links. Basically, the idea is that value objects are part of the domain (which is mutable) and therefore should not go into messages (which are immutable).
There is some truth to that, but don’t take these opinions too literally. The fact that value objects are part of the domain, doesn’t make them mutable. Value objects are mutable. Moreover, messages are also prt of the domain. They describe interactions, just like many of your entities should.
If anything, make sure the objects you put into messages are value objects. Messages are immutable, so any object referred to in them, must be as well.
The truth in the ‘don’t use VOs in messages’ is in the fact that value object may evolve over time, as our (understanding of the) domain changes. This would also change the structure of messages, which may cause compatibility issues somewhere else.
My recommendation is to be careful using VOs in messages. Doing so when a value object represents a widely accepted and standardized concept, such as Money (currency + amount) or address, chances are very small that you’ll run into these problems. Value objects used in a models of a domain that is still being explored, is not ideal.
Hope this clarifies things.
Thanks for your insights Allard and Brian!