Immutability
Strive to make your classes as immutable as possible.
The OOP community learnt this lesson much earlier than we tend to think : Mutability makes the code harder to understand.
Immutable Code
Have you heard of the Gilded Rose kata by Terry Hughes ? It's a perfect illustration of why mutability must be avoided as much as possible, and self-contained deep and far away from us.
Please, take a seat, breath deeply, and look at this code carefully.
Do you understand the mechanisms behind that code ?
What are the business rules ?
What with these magic strings and magic numbers ?
Why 50, 11 or 6 ?
If you're not familiar with the exercise, you're probably lost and may as well give up.
The main problem of that code, other than the fact that's it is not object-oriented, is its mutability.
The quality
and the sellIn
property of the items are constantly changing, making it all the more difficult to comprehend.
The item
object is having an identity crisis. It's not even an object, it's a data-structure.
Here, the solution isn't to make Item immutable, though it can be one potential way of solving this problem.
The exercise forbid changing the Item class anyway, it's part of the difficulty.
The solution is to instead capture the intent (namely, updating the quality of a product) and grouping the mutations in the end. That's the whole purpose of the exercise.
Below an example of solution.
When methods are names instead of verbs, you either have getters or objects waiting to appear.
See how much more clearer the code is ? We got rid of all these nested loops and mutations and checks and extracted the real intent of the code inside well named functions and tiny refactoring steps (just the refactoring would warrant a full article by itself).
But the most important point is the immutability. We grouped the change at a single spot of the function : the end. The change in quality is represented inside a delta
, and we perform the mutation at a single place.
In the absence of switch expressions we must rely on extracting the pattern matching code inside a function named qualityUpdate
. If your language supports a form of pattern matching, consider using it instead of creating another function.
Immutable Objects
If there's one thing we learnt from many decades of computer science and software engineering, it's that mutability is the source of many problems. It makes it very difficult to track the evolution of an object and to work with multiple threads.
But most importantly, immutability is much easier to reason with.
Think about it.
This little program computes the result 3
.
But should this computation change the value of 1
?
Should 1
become 3
?
We could get philosophical, but we can both agree that changing the value of a number would be terribly disturbing.
Same goes for objects. Or is it ?
One huge clash between immutability and object-oriented programming is statefulness. In the purest OO paradigm, objects maintain boundaries between their internal world and their external world. From the outside, calling the methods and invoking the services of an object may and will probably alter the state of that object.
Imagine publishing posts or creating an account into system. Doing so would definitely change the state of the system.
So is OO incompatible with Immutability ?
Not so much, because OO is a rather wide term, and not every objects of our program can be considered a system.
I find that some objects are a better fit for immutability than others.
Take Value Object. It's a pattern in which a value is encapsulated into an object to enrich its meaning and capabilities.
Every Value Object is immutable by definition. Two Value Objects are the same if their internal state are equivalent (their bit representation is the same). And most value objects have arithmetic operations.
Think of a Seconds
class that represent a time delay in seconds.
Every operation creates a new instance, and that's perfectly logical. Adding seconds should not change the meaning of any of the operands, it should yield another value.
So I found that an object is a perfect fit for immutability when either :
Two objects can be considered equal simply by comparing their bit representation
The object has some form of arithmetic
Long-lived objects such as Entities aren't a good fit for immutability because they carry a persistent lifecycle. Changing the name of the user shouldn't yield another user. It's the same person, but with a different name.
Last updated