Classes should be immutable unless there’s a very good reason to make them mutable….If a class cannot be made immutable, limit its mutability as much as possible.
Joshua Bloch, Effective Java
So, what should be a potential reason to make the classes mutable? Let’s have a look at the definition of immutability:
Immutable Object is an object whose state cannot change after creation.
Now it is clear – this is the change. Objects whose nature is changeable are inappropriate candidates for immutable ones. Frequent changes are a perfect reason to make them mutable. But how to distinguish ones from the others in practice? There are already very helpful concepts coming from Domain Driven Design which allow us to do it easily.
Value Objects
Let’s start with immutable objects that should be somehow easier – all in all, we are on the immutable side of power, nowadays with a hype of functional programming. However, if immutability is not a native feature of the language, then there are some indications, showing when to use immutable classes. It turns out that these are values – abstract data types, enumerated types, constants, numbers, events. (It is not surprising to find that String or Integer are immutable in java.)
Domain Driven Design specifies it more precisely:
- Value Object has NO identity. However, two VOs with the same values are equal, and therefore can be interchanged. Equality is based on the state but not on the id.
- Value Object has NO life cycle. They can be easily created and destroyed. They cannot live on their own, and always belong to some Entity.
- Value Object knows everything about itself; it is good place to include processing logic.
Now, let’s try to identify the Value Objects. If you imagine ShoppingCart,there’s probably some Quantity of Products, and a summary with certain amount of Money. Quantity and Money are our first shot – these are real Value Objects. Here comes the abstract concept:
Quantity
————–
amount: Number
units: Unit
————–
+,-,*,/
<,>,=
…
And here is one of its representation implemented:
public final class Money { private final BigInteger amount; private final Currency currency; public Money(final BigInteger amount, final Currency currency) { this.amount = amount; this.currency = currency; } public Money add(final Money money) { assertCurrency(money.currency); return new Money(amount.add(money.amount), this.currency); } public Money subtract(final Money money) { assertCurrency(money.currency); return this.add(new Money(money.amount.negate(), this.currency)); } public boolean equals(Object arg) { if (!(arg instanceof Money)) return false; Money other = (Money) arg; return Objects.equals(this.currency, other.currency) && Objects.equals(this.amount, other.amount); } public int hashCode() { return Objects.hash(this.amount, this.currency); } }
The code above is self-explanatory – it is final, immutable; represents value; identity is based on all properties; can calculate itself and, what is important to notice, can be shared between different entities like Product itself and the ShoppingCart (as a price).
10 EUR is always 10 EUR. It’s not going to change (from a logic standpoint of view). Potentially you can convert it to some other Currency.
public Money convert(final Currency currency);
Now there is no more 10 EUR, but some other value. In contrast, we can intuitively find a ShoppingCart being changeable, but still with the same value, even after number of operations made on it.
Now, let’s talk about the other, more abstract type of Value Object. Quite a popular example of Address. You can think about it as a Value Object in the situation when you are not interested in it’s unique identification. It might happen that Address is just additional information hold together with Customer (as group of columns in the entity table).
public final class Address { private final String street; private final String city; private final String country; private final String postalCode; public Address(final String street, final String city, final String country, final String postalCode) { this.street = street; this.city = city; this.country = country; this.postalCode = postalCode; } public boolean equals(Object arg) { if (!(arg instanceof Address)) return false; Address other = (Address) arg; return Objects.equals(this.street, other.street) && Objects.equals(this.city, other.city), && Objects.equals(this.country, other.country), && Objects.equals(this.postalCode, other.postalCode); } public int hashCode() { return Objects.hash(this.street, this.city, this.country, this.postalCode); } }
The second role of Value Object is to group related properties into one class. And most probably, Address of Customer can change, but it is ok – as far as it is immutable on its own.
Entities
Whole Item 15 of Effective Java is about Value Objects – check the examples there. But it is also said there:
Immutable objects make great building blocks for other objects, whether mutable or immutable.
There are the mutable ones which are Entities.
Entity term may be sometimes misleading. That’s why it is also called a Reference Object (any change on such object needs to be visible to all places it is referred from). However, I will stick to the Entity, mentioning only that it is said in the meaning of DDD.
- Entity has always a unique identity. Such two objects are considered to be equal if the id is the same. (You can think of it as PK in a database).
- Entity has a life cycle. It has a state, is mutable and runs through time.
- Entity is a reach business object representing real-life entity which deals with Value Objects.
It is quite easy to find out that Product, Customer and ShoppingCart are Entities in our example. They are uniquely identified and change in time. Let’s check out what they could look like.
public final class Product { private final String id; private final Money price; ... public Money calculatePrice(final Quantity quantity) { // return the Money being multiplied by quantity } ... }
public final class Customer { private final String id; private final Address address; ... public void changeAddress(final Address address) { ... } ... }
public final class ShoppingCart { private final String id; ... public void add(final Product product, final Quantity quantity) { // collect products increasing quantity value } public Money calculateTotal() { // with each collected Product.calculatePrice(quantity) // and sum } ... }
Of course, these are simplified examples and their mutability could be avoided for light objects. However, when it comes to objects that frequently change, then it is very good reason to be mutable. If we’ve got a lot of business rules, conditions and methods inside a single object then most probably it is our mutable, real-life Entity. Mutable entities are also designed for CRUD where the use of immutability would contradict the application. If we went for immutability everywhere in an imperative language, then we would end up with lots of boilerplate code being just technical solution for non business issue (copies everywhere, trains to nowhere). It is questionable and subjective, but from my point of view, such code is much harder to read.
Limit mutability
Still, we should try to limit mutability as much as possible. Value Objects are here to help – they are good building blocks. We can delegate calculation to them and keep only necessary things. (And yes, it is true, that it is much harder to design collaboration between Entities, but let’s not focus on that topic today.)
We should also avoid setters – in the meaning of methods changing a state. Introduce only the ones that the business is interested in. Entity could have a different number of properties, but only one can change from the business point of view. The others stay final.
We can also think of immutable entities. This knowledge also comes from the nature of our domain. The example could be an Invoice document that cannot be changed, and is still being identified by its id.
Services
Services are again out of the scope of this post but I will just enumerate some things.
We should take care of drawing boundaries carefully and with respect. Create stateless services that will work as a proxy to our Entities. Make them like containers, in which the single case is handled. Let’s not allow them to leak out anywhere. The biggest chunk of business should be placed in Entities and Value Objects (avoiding anemic model). Let them orchestrate – find the Entities, perform requested operations on them and most probably store it afterwards. Let’s do it only there but not in resources, controllers or repositories. Return transformed representation on a query. Last but not least, assign proper responsibilities to the objects – even to the technical ones.
Concurrency
Finally, I have to mention the question from the beginning – “to mutate or not”. However, I won’t do it widely.
Mutability is for sure the enemy of concurrency. It’s so easy to generate a bug, and very hard to find the reason of it. Synchronization and locking are complicated. When we care about proper responsibilities, then we also control whether our Entity could be a shared resource. It shouldn’t be, if it is mutable. However, we can synchronize reading and writing stuff with Memento Pattern – (proxy again), and care about thread-safety of concurrent operation, and still not complicate Entity itself with immutability.
If you run batch processing chunked into threads, the work should be distributed consciously – for example threads could work with different parts of data.
So, if you are in multi-threaded environment, you know that you will share objects between threads and so on, then think about their immutability. The choice of language for your job is an option too. Try to think about your objects from a business standpoint of view, when trying to identify your Value Objects and Entities – immutable and mutable ones.
Summary
For the summary I will just quote Brian Goetz from his paper “To mutate or not to mutate”:
Some data items remain constant for the lifetime of a program, whereas others change frequently. Constant data are obvious candidates for immutability, and objects with complex and frequently changing states are generally inappropriate candidates for implementation with immutable classes.
In my opinion such observation comes from the nature of real-life entities. The observable change of their state implies the mutability.
Reference
- Quantity by Martin Fowler
- ValueObject by Martin Fowler
- ReferenceObject by Martin Fowler
- Evans Classification by Martin Fowler
- To mutate or not to mutate by Brian Goetz
- Difference between Entities and Value Objects by Philip Brown
- Entity vs Value Object – the ultimate list of differences by Vladimir Khorikov
- DDD Quickly at InfoQ