Looking through the programming presentations on Speakerdeck I found one created recently by Michael Fairley entitled Immutable Ruby.
Michael suggests a technique to ensure that information in an application which is thought of as unchangeable actually stays this way. There are plenty of transformations that can corrupt data, and so I agree that it is probably a good idea to be clear about what should be out of scope for manipulation.
To this end, I will reproduce a few techniques that Michael Fairley puts forward in his presentation. The deck is actually quite long and covers a bunch of other interesting topics (such as: deep freeze with ice nine, and event sourcing), so for more depth please visit his presentation.
Creating an immutable module
Lets suppose you are running an online store where you have a purchases table that records previous purchases.The table might look like this:
1 2 3 4 5 |
|
There would be little reason to change this data, so it seems likely you would want to make it immutable to protect its integrity. Thus, it would be helpful to have an immutable module, like so:
1 2 3 |
|
To make an immutable module, only 5 lines of code are needed, as follows:
1 2 3 4 5 |
|
Now, if we try to update data on the purchases table, the change does not go through:
1 2 |
|
Harnessing active_record with the immutable_attributes gem
Wouldn’t it be great to control mutability on certain fields? The immutable_attributes gem allows this: github.com/JackDanger/immutable_attributes gem install immutable_attributes
Now we can harness ActiveRecord to make the fields on the purchase table immutable, as follows:
1 2 3 4 5 |
|
Using the freeze method
The problem
We might start with a method that will build a full url for a part of the application based on some params. This may look as follows:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Although this code may look like it works, in actuality it may generate some problems as follows:
1 2 3 4 5 6 7 8 |
|
What is going on here? There is only one instance of the ROOT_URL being created, which is then passed into the build_url method over and over. In the build_url, the shovel operators (<<) are mutating this single instance of the string.
Fixes
One simple way to fix this would be to replace the “<<” with =+ in the code.
A better way would be to use a freeze method on the ROOT_URL, forcing the application to raise an exception if the string would be mutated. this would look like this:
1
|
|