I wanted to bring my question to the bigger audience as we already discussed for some time in our company and cannot find an answer.
Let us suppose we have Transaction object which is aggregate root. Inside Transaction we have Money which is value object.
class Transaction {
private Money money;
// other stuff
}
and
class Money {
private BigDecimal amount;
private String currency;
}
Such Transaction can be persisted (we use hibernate) to db into simple table transaction
+-----------------+
| transaction |
+-----------------+
|id : bigint |
|amount: decimal |
|currency: varchar|
|other... |
+-----------------+
And everything would be great but... customer requires us to have currency table in database (we call them dictionary tables) and every table (including transaction) that have money need to point to the currency table:
+-----------------+ +-----------------+
| transaction | |curency |
+-----------------+ +-----------------+
|id : bigint | +---> | id: bigint |
|amount: decimal | | | code: varchar |
|curr_id: bigint | ----+ | name: varchar |
|other... | +-----------------+
+-----------------+
So from now on, Money object should look like this:
class Money {
private BigDecimal amount;
private Currency currency;
}
And from now we cannot call it value object :( or can we? It also complicates the way we are persisting the object as we cannot use hibernate embedable any more as we need to write our own custom type enter link description here. For sure we are not the first one facing this problems as dictionary types are popular in use, question is, how to treat them in scope of ddd modeling.
We will face similar problem when dealing with adresses. So, we know we have dictionaries like Country and FederalState (which are hierarchical). And we also know that many object in our application (e.g. Institution) have thei own adresses but also have connection to FederalState. So in simpe case we would have:
class Institution {
Address address;
// ...
}
where
class Address {
String street;
String houseNo;
// etc..
String federalState;
String country;
}
But we need it to have relation to fedral state table, therefore Address will look like:
class Address {
String street;
String houseNo;
// etc..
FederalState federalState;
}
so we face again the same problem, Address is not value object from now on. We know how to do it technically but what is the right approach from the perspective od ddd?
The main difference between entities and value objects lies in the way we compare their instances to each other. The concept of identifier equality refers to entities, whereas the concept of structural equality - to value objects. In other words, entities possess inherent identity while value objects don't.
Value Object is an object that represents a concept from your problem Domain. It is important in DDD that Value Objects support and enrich Ubiquitous Language of your Domain. They are not just primitives that represent some values - they are domain citizens that model behaviour of your application.
A domain entity in DDD must implement the domain logic or behavior related to the entity data (the object accessed in memory). For example, as part of an order entity class you must have business logic and operations implemented as methods for tasks such as adding an order item, data validation, and total calculation.
A value object can reference other entities. For example, in an application that generates a route that describes how to get from one point to another, that route would be a value object.
"what is the right approach from the perspective od ddd"
First of all, using dictionary entities is not wrong. Be it only for the reasons that, unlike a string value, using a relation to a dictionary entity:
Letting aside the two above, business requirements may impose this design. E.g. for the Currency
case: when expressed as an entity allows the definition of the Exchange Rate
relation, which in itself may be subject to an 'auditable record/history' approach for storing the evolution of the exc.rate over time.
Having a State
dictionary is a good base for (possible future) extensions handling different sale tax policies, or legislative restrictions (product/service not allowed in some states - see 'medicinal' weeds and what not).
There is a good post https://enterprisecraftsmanship.com/posts/nesting-value-object-inside-entity/
Curency in your example are clearly value objects. You can create an wrapper Entity CurencyInTransaction on Value Object Currency and put business logic in Currency.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With