I was thinking about some entities I need, when I came across a very interesting concept: Immutable Objects.
The Immutable Objects are very handy to manage the so called Value Objects.
In the Domain Driven Design (DDD) properties of an Entity
can have two different values: other Entities (Order->getProduct()
– here Product
is an Entity
and its properties can change) or simple values (Product->getPrice()
).
Price
, in our example, is a simple value, not conceptually an Entity
. Until now, it probably is a simple property in your Entities (as it was in mine!).
But, in this second case, the Value Objects play their parts: they represent those values in an immutable state.
In fact, if you reflect about the data Price
, you realize that a Price
is something like “100 Eur”. If you put your attention on the value, you can recognize more than one smaller parts in it: a numeric value – 100 – and a string value – Eur.
A Price
is a Price
only if we indicate both the numeric part of it (100) and the string part of it (Eur): If we indicate only one of the two, it is not a Price
because we don’t know how much money does it represents or in which currency the price is expressed.
So we need both the “amount” and the “currency” to have a real value. Think it as a “composite value”.
And the important thing to consider to understand what Immutable stands for: if in the Price
we change the amount, we have a different price. If in the Price
we change the currency, we have, again, a different price.
But if in a Product
we change the Price
, we don’t have a different Product
but the same one with only a different Price
.
What an Immutable Object is?
Using some words written by others:
A value object is a class (usually small, with just a few properties, and frequently used), that represents a value which has no identity separate from its properties. If any one of its properties change, it is no longer the same value.
An example of a value object is an address. If you change any part of an address, it becomes a different address. Another example would be a price – it might have properties for currency, amount, and payment frequency, but changing any of those would yield a new price.
As such, value objects are immutable – their properties cannot change (it is normal to use getters but not setters for the properties of value objects). If two value objects have exactly the same properties, they can be regarded as equal.
Value objects can have methods, but the behaviour of a method doesn’t ever change the object’s state. If a method needs to change a property, it will return a brand new instance of the value object instead of modifying the existing one. Methods on a value object can also return other types of value of course (eg. a boolean return value would be typical for a validate method).
So, if a Product
with a different Price
is ever the same Product
(read: THE SAME Entity
Object, only with a different Price
. PHP will recognize the different Price
as a modification of the original Product
PHP Object), then a different Price
is something completely different from the previous Price
(read: it is A DIFFERENT Value Object and for PHP the two Prices are two different and separate objects).
Those behaviors are obtained writing the code of the two kind of classes (Value Object or Entity
Object) in different ways and implementing methods with different behaviors when we interact with the Objects.
So, knowing the conceptual differences between a pure Entity
Object class and a Value Object class permits us to write more solid code and better organize our business logic.
A simple example of an Immutable Object
So, as you can see from the example, this small class respect all the constraints of the definition of “Immutable Object”:
- Represents a value which has no identity separate from its properties;
- Its values can be passed only through the
__construct()
and so it hasn’t setter methods ($this->__set()
is even overridden and with no body to prevent accidental modification to the properties); - It returns a brand new instance of
Email
if a change is required.
And it is also really small as class!
How to manage Value Objects using Doctrine
Starting since the version 2.5, Doctrine supports the use of Value Objects, calling them Embeddables.
Embeddables are classes which are not entities themself, but are embedded in entities and can also be queried in DQL. You’ll mostly want to use them to reduce duplication or separating concerns. Value objects such as date range or address are the primary use case for this feature. Embeddables can only contain properties with basic @Column mapping.
This is a simple example of an AddressEmbeddable
implemented in a dummy User Entity
:
<?php
/** @Entity */
class User
{
/** @Embedded(class = "Address") */
private $address;
}
/** @Embeddable */
class Address
{
/** @Column(type = "string") */
private $street;
/** @Column(type = "string") */
private $postalCode;
/** @Column(type = "string") */
private $city;
/** @Column(type = "string") */
private $country;
}
The advantages
Before Embeddable, we could only do two things to manage a Value Object (as the AddressEmbeddable
is):
- Create an
Entity
Address
and use the relationOneToOne
orManyToOne
/OneToMany
(OneAddress
for oneEntity
or, alternatively, oneEntity
with manyAddresses
) to associate the two values; - Create the required fields directly as property of the
Entity
.
No other ways. But those two ones have some drawbacks:
The first alternative, create a new Entity
, means a new table is created in the database (to contain Addresses
), so the resulting schema is something like this:
|---------------------| |--------------------------------------------------|
| TABLE USERS | | TABLE ADDRESSES |
|---------------------| |--------------------------------------------------|
| id | name | Address | | id | street | postal_code | city | country |
|---------------------| |--------------------------------------------------|
| 1 | John | 1 | | 1 | Via di Qui | 12345 | Naples | Italy |
|---------------------| |--------------------------------------------------|
Two separate tables linked each other by a foreign key. Each query needs a JOIN
to get in the same resultset both the User Entity’s data and the email.
The second alternative, create the required fields in each Entity
, on the other hand, is a solution that doesn’t permit to perform some checks, for example about the validity of passed data (see the example above of the Email
: when instantiated, the Email (Value) Object checks that the passed data are really an e-mail).
If you’d like to do this type of checks, you need to repeat the same code in more Entities, and, if you make a change, you have to update the code in more places (not speaking about unit tests!). Not so useful, not so practical, not so intelligent, not so easy.
Using an Embeddable object, instead, permits you to take advantage of only the benefits of the two methods.
Embedding the AddressEmbeddable
in your Entities, will produce a table like this:
|-----------------------------------------------------------------------------------|
| TABLE USERS |
|-----------------------------------------------------------------------------------|
| id | name | address_street | address_postal_code | address_city | address_country |
|-----------------------------------------------------------------------------------|
| 1 | John | Via di Qui | 12345 | Naples | Italy |
|-----------------------------------------------------------------------------------|
Very useful!
NOTE: The default behavior is to call the column [embeddale]_[property]
([address]_[street]
), but you can change it.
The last essential question: Which is the best way to represent a domain: an Entity
or an Embeddable/Value Object?
So, here we come to the very complex question: what kind of class should have I to choose when dealing with such a decision?
Also if the question seems complex, the answer is really simple: it depends 🙂
A value object is a class (usually small, with just a few properties, and frequently used), that represents a value which has no identity separate from its properties […]
So, an Address
without the postal code has no sense, but a Company
without an Address
has.
A Price
has no sense without a Currency
, but a Product
without a Price
has.
So, use Value Objects/Embeddable each time you have to represent a value composed of more than one information and only the sum of these information has a sense and “creates” the meaning of the value. You can also use Embeddables in other Embeddables, for example you can use a PostalCodeEmbeddable inside the AddressEmbeddable
(not tested, but I think it’ll work fine).
Each time you’ll find those kind of objects, you’ll know they cannot be modified in any way and that, if you edit them, you have a new different Object, not the same edited.
The problem: and if, for example, a Customer
can have more than one Address
(for example, one time it chose to ship to Italy and the second one it chose to ship to UK)?
The problem arises when the Embeddable is melted into the Entity
table: only one Address
is allowed.
The Real Astonishing Truth: Entities and Value Objects/Embeddable can be used together!
Yes, it is possible to use together Entities and Embeddables.
So, if a Customer
can have more than one Address
, and as you can use Embeddables/Value Objects together with Entities, you’ll have an AddressEmbeddable
that represents the current state of the value and an AddressEntity
that represents the collection of those values.
Something like this:
<?php
namespace AppBundle\Entity;
/** @Entity */
class User
{
/**
* @ORM\OneToMany(targetEntity="Address", mappedBy="ofUser")
*/
private $addresses;
}
<?php
namespace AppBundle\Entity;
/** @Entity */
class Address
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="addresses")
* @ORM\JoinColumn(name="of_user", referencedColumnName="id")
*/
private $ofUser;
/**
* @Embedded(class = "AddressEmbeddable")
*/
private $address;
}
<?php
namespace AppBundle\Embeddable;
/** @Embeddable */
class AddressEmbeddable
{
/** @Column(type = "string") */
private $street;
/** @Column(type = "string") */
private $postalCode;
/** @Column(type = "string") */
private $city;
/** @Column(type = "string") */
private $country;
}
This way you’ll have again a table dedicated to addresses, but each Address Entity
will return an Immutable Object, one that returns a new object if edited (IS UP TO YOU TO IMPLEMENT THE AddressEmbeddable->setNewAddress()
method in such a way it returns a brand new copy of the AddressEmbeddable
class. See the Email
example above to better understand this).
Someone terms “Fake” this kind of Address Entity that embeds an EmbeddableObject because its unique purpose is to manage an Embeddable.
If seen only in the context of Doctrine, this could also be considered true, but, if considered in the bigger picture of the Domain Driven Design, this is the only correct way of doing things.
The real purpose of a Value Object is to represent an Immutable Value. The fact that Doctrine calls them Embeddables and treats them in some ways persisting them into the database is something that does not interfere with the real purpose.
So, the Entity
is a container of values and a value formed by more values has to be a Value Object instead of a simple property.
Using Doctrine, those Value Objects are called Embeddables and are persisted creating columns directly in the table of the Entity
that embeds.
But the concept of Immutability applied to Value Objects still is valid and has to be used, independently of how the ORMs manage their persisting in the databases.
Some links to go deeper
- http://stackoverflow.com/questions/31183954/why-to-use-getter-setters-for-doctrine2-classes
- http://blog.sznapka.pl/immutable-value-objects-in-php/
- http://welcometothebundle.com/price-more-then-money-php-library/
About Doctrine and Embeddable/Value Objects:
- http://welcometothebundle.com/persist-the-money-doctrine-value-object/
- http://doctrine-orm.readthedocs.org/en/latest/tutorials/embeddables.html
- http://rosstuck.com/persisting-value-objects-in-doctrine/
- http://russellscottwalker.blogspot.it/2013/11/entities-vs-value-objects-and-doctrine-2.html
- http://stackoverflow.com/questions/7375334/immutable-collections-in-doctrine-2
Remember to “Make. Ideas. Happen.”.
I wish you flocking users, see you soon!
Michele Nasti says
For my experience, if an entity can have one-to-many relationships (a person can have multiple addresses, email, etc.; a product can even have multiple prices… !!!) you can simplify it at the start, but all of a sudden the problem will come and find you!! Better to design carefully.
This level of complexity (brought by the domain driven design) is usually not needed, I mean I’ve developed systems without immutable objects and no problems have arose; I still can’t understand the real point (the killer feature!) that you can achieve with this approach.
Aerendir says
A value object is something different from an entity.
Yes, it’s possible to not use Value Objects with immutability, but the fact that you can do something in a way doesn’t mean you have to if a better way exsists.
So, if it’s true you can better design an entity, thinking this you should consider that the concept of Value Object is something quite different from the one of Entity and that they serve two completely different purposes.
Think at the built-in PHP DateTime class: it’s the best example of a value object.
Using this class simplify your work, not complicate it.
An example from the real world (not built-in PHP, but written in PHP by a common PHP developer) may be VDB URI: it’s a very advanced Value Object that represents an URI and that can manipulate one and perform some useful actions with one or more of them. It simplify our lives, not complicate them.
Abelardo says
I am trying to understand the Value Object concept and, more specifically, its immutable property.
Let’s talk about Price as an example of Value Object.
As you told inside this post, the concept behind of Value Object tell us this should be immutable.
By other hand, a product can vary of price (sales off, etc.) and to be the same product (a book is the same book even when its price varies).
Although conceptually a Value Object is different than another one because its value differs, what’s the disadvantage of reusing a Value Object?
I don’t understand the importance of being immutable.
Good post. 🙂 Kindest regards.
ABELARDO says
I follow with my comment:
Immutable property has sense if you are going to reuse a Value Object (e.g.: Price(100 €)) for other situation…but it could be possible if you serialize it to reuse later.
If you aren’t going to reuse it, what do you care about to change its value? If you wouldn’t like to change its value, why don’t you define it as a constant?
Kindest regards.
Aerendir says
The first advantage is that it avoids bugs.
See this snippet of code in our `FeaturesBundle`: https://github.com/Aerendir/bundle-features/blob/master/src/Service/FeaturesManager.php#L755-L783
To understand I need to `clone` the `DateTime` object I spent a lot of hours. Maybe someday we will switch to `DateTimeImmutable`.
Coming to the conceptual questions, it is possible you reuse Value Objects: think at an operation on it, like a sum or a subtraction.
Knowing that it is immutable, you are forced to create a new Value Object that represents the two operands: if you don’t use Value Objects you may be tempted to simply change the value, and this may lead to really difficult bugs to spot.
A book can be implemented as a value object or as as a POPO (Plain Old PHP Object): but, you need to distinguish the concepts: the title of a book is immutable: if you change the title you are changing the book; if you change the price, you are not changing the book itself, only its price. But the price itself is not a modified price but a completely new price, different from the previous one (`$newPrice !== $oldPrice`).
In the end the choice about immutability and concrete implementation as a POPO or as a Value Object is up to you.
For sure there are some kind of information that must be immutable like prices, dates, weights.
More, this is something that is applied also to values that have a meaning only when there are at least two bit of information, like for the prices: 10Euro is composed of a numerc part (10) and of a currency (Euro): if you only use one, you don’t have a Price but only a value.
Ahmed says
And where are the setters and getters? If an embeddable can’t have them, you still have to duplicate code for every entity using it, right? I don’t see the point honestly.
Aerendir says
Can you better explain what are you saying? I’m missing your point…