PSA: Immutable Data can Help You Avoid Pesky Bugs

In my experience as a developer, I have come to the above conclusion. Immutability is an extremely important concept to understand, especially as your application balloons out of control.

This will be a largely anecdotal article, but my gut says many people have encountered the issues and noticed the pain of an aging application. Ever submit an item to an API and noticed a $$hashKey property on your data model? Ever wonder why a date is formatted as 12/18/2017 when accessing an page from one route and December 18, 2017 from another route?

These problems come as a result of being able to mutate data. Many developers, myself included, focus on a specific problem while addressing a ticket (adding a feature, fixing a bug). In my experience, this leads to a lazy solution. Date not formatted right? When the component is initialized, format it! $$hashKey present on your data model? Create a request object from the data model and write out all 35 properties one by one until you exclude view data!

As time goes on, this leads to a mess of code. If statements galore, extra steps to interact with the API, difficult to debug problems, the list goes on.

Story Time

I could probably best explain this through a story in which I reviewed code very similar to what you see below.

You can see from the above codepen that the push of the Select... option bridges the component boundary without being coupled in the code with the exception of the selector.

The developer was attempting to make an option in a drop down be the default state of Select... to the user. This represents a non-selected item in the dropdown. What the developer did not realize is that the reselect library memoizes the data. If the store reference did not change, then the myCollection property will be returned next time the selector is executed.

Since the array reference remains the same and an item added via push, this means next time MyDataSelector is used, it will return the same collection, but with an additional Select... option! This presents itself in a strange way if that selector is accessed from two different pages and it only happens when Table.component is accessed first!

Immutable Solution

The solution to this problem, and more, is to use an Immutable library. I am familiar with one library, specifically, called Seamless Immutable. Seamless Immutable presents very useful error messages when attempting to mutate the data within the immutable object. When mutating the data, it returns a new reference, such as when using the set method on an object. If we attempted to push to an Immutable object, we would see something similar to the error below:

The push method cannot be invoked on an Immutable data structure.

This would be the first sign to the developer that something was being done wrong. There are two things that can be done from this point. We can either:

a) Add a new selector that returns an array with a Select... option in it to be utilized throughout the app

b) Use concat to create a new array reference local to the component

In either case, we’ve solved the issue! We no longer have an array reference returned by the selector that contains the Select... option.

Now, there are scenarios in which we do want a mutable object. For instance, we may want to create a data model for our view to utilize and manipulate that is derived from our store of information. Seamless Immutable provides an asMutable method to do just that, as well.

Lessons Learned

Immutable data helps prevent some bad practices that I’ve found in developing large scale applications such as:

  1. Manipulating data passed into a component via bindings (React, Angular etc)
  2. Using the wrong iteration method (i.e. manipulating references as a way to set a property on an object, instead of using a map function)
  3. Being unaware of what your libraries are doing/require (i.e. $$hashKey being added when not using track by in ng-repeats)

These are just some of the benefits. One other benefit is seeing the asMutable method being used is a pretty big indicator to somebody doing a code review!

As applications become larger and the number of use cases and features increases, the more benefit Immutability provides. Consider the centralized data stores such as Redux or Angular services that are injected/utilized in multiple components.

Hopefully, this blog will help you gain some curiosity in the concept of Immutability. It has been a huge life saver when it comes to libraries such as Redux where data stores are utilized in dozens of components and needs to be manipulated for each use case in the application. I hope that the concept can work its way into yours and provide some benefit!