The Case for Immutability
Immutability is the notion that something cannot be changed. It has become a buzzword lately because of its pervasiveness throughout modern languages like ClosureScript and Elm. Why would you want data that can never change, when data is constantly changing in modern applications? One of the harder problems to solve for is how to detect when data has been updated. When we know that, we can update all of the pieces that need to respond.
There’s no trick to this example. We’re taking a variable named data, and creating a newData variable that is equal to the original. When we check if the two variables are equal, as expected it’s true. When we change the value of newData and check the equality again, as expected, we see that they are unequal, thus the newData has changed.
This works because when we declare the data variable, it is immediately given a value. Then we do the same with newData and set its value to the value of data. When we set the value of newData to something else, as expected, it is not equal to the value stored in the data variable.
So how do we solve for this? It’s actually easy, we just make a copy of the original object when we create our second variable, using the Object.assign method.
Object.assign copies subsequent objects’ properties into the original object that is passed to it. What we’re doing in the code above is creating a brand new object, then copying the properties from data into it, and then copying any new properties, giving a brand new object. Another positive from embracing immutable data is that our data becomes way more understandable. We now know that data is different from data2, and how it is different. Alternatively, if you just wanted to create an exact copy of an object, you could also use the Object.create method.
Likewise, when dealing with arrays, you’ll find the following.
Using React as an example, you can tell your component to only update when the data it is watching changes. Using immutability, this becomes very simple, and it is now easy to write highly optimized components.
This works just the same as before, the syntax is way more natural than using Object.assign or .concat, but it becomes obtuse when working with more complex data.
We find that we are constantly spreading in different layers of data. For me, this feels a little too verbose, especially when dealing with something as simple as updating one property on a nested record. We also have the problem that whenever we attempt to update a record, even if the data doesn’t change, we are returned a new object. We are effectively now able to test if an attempt to change data was made, but not if the data was actually changed.
Luckily, there’s a library named Immutable.js, written by Facebook, that provides a very robust suite of Immutability helpers. Not only is the syntax much cleaner using the Immutability library, but manages your state as a set of smaller objects, internally. Here’s how we’d solve the same problem with Immutable.js:
Let’s look at a real world example. Let’s say we’re building a friend list, and we only want it to re-render when the data it cares about is changed. Let’s say the friends list relies on a total user count, whereas individual user items need to update when any map of properties changes.
We can see the list component will only update when the user information changes and likewise, the list item component will only change when the information that it’s concerned with is updated. When using Immutable.js, we don’t have to worry about new memory allocations being created for objects unless the data actually changes, which means that we can be sure that the user interface only updates when data actually changes.