the case of immutable js
By Per Fröjd
- javascript
An opinionated case of ImmutableJS
Coming from an outside perspective of data integrity, immutability, I first heard of the concept during the early days of React and Redux. Dan Abramov made the distinction for me in his series, Getting Started with Redux. Then again, this is not a blogpost regarding immutability as a generic topic.
After learning more about immutability together with Redux, it seemed pretty straight-forward, but I recall sticking with using the Object.merge
and Object.assign
-functions available, and calling it a day. Further down the line, as Redux increased in popularity, Immutable.JS appeared and various communities immediately started buzzing about it, including it in various boilerplates.
Attempting to integrate ImmutableJS into a sample Redux project proved fruitless for me, I kept hitting issues where Redux, and myself, expected these immutable lists and maps to work like their native counterparts. At the time, this wasn’t a eureka moment, but now (maybe a year later), I can definitely see why I hit these issues.
Recently, I finished up a smaller project at work where I decided to throw a curveball for myself and my fellow colleagues. By discarding Redux (it didn’t fit the concept) and going plain ol' React, but using ImmutableJS wherever applicable. Initially, the learning curve was somewhat steep as I wasn’t used to syntax, and was lacking experience regarding the common uses of Sets, Maps and Lists that ImmutableJS offered.
I quickly noticed that, excluding the docs, ImmutableJS didn’t have such a big impact to the community as I thought, back when I was learning Redux. Most of the community-written articles and blog posts dealt with integrating the library with Redux, but not much further than that. Guesswork turned into frustration, when I seemed to have issues understanding how to use methods like updateIn
, setIn
and merge
but found little to no examples.
So I took a weekend, sat down and created test-cases for the methods I didn’t get with example data and as complex use cases I could think of. This came to be the start of a cheatsheet that was used frequently throughout the development.
Weeks later, I stepped out of the project for a month (small development team, this happens more often than I’d like) and a colleague sat down to continue the project. We had a small meeting regarding the changes I had introduced to our usual workflow, I linked him my cheatsheet and went on my merry ways.
Up until this point, my opinion of ImmutableJS was rather positive. Modifying and dealing with data changes felt easier and I enjoyed the change. So far, we had only added one external component to our project, and it took some workarounds for it to be able to deal with the ImmutableJS types. This didn’t bother me much to start with, I had no intention of modifying the component (as it felt like much more effort than simply calling toJS()
and fromJS()
as data entered and exited the
component).
Returning to the project, an additional pair of externally downloaded components had been added, with the same workarounds. The code started to annoy me somewhat, was this an issue every single user of ImmutableJS would deal with? We happened upon some really hard to trace bugs, where components were expecting plain ES5 arrays and objects, but were using standard methods like .filter
and .map
. Turns out ImmutableJS is still compatible with the way those methods are used for the ES5 types,
and instead errors occurred much deeper in the stack.
Learning more, as you do during the development of a project, I found that much of the code I had written at the start of the project could be optimized. I could swap .map()
-calls containing individual .set()
-calls by simply using setIn
. .find()
-operations would replace combinations of .findIndex()
and .update()
. It also occurred to me that the change of workflow was much larger than I had anticipated. I mean, it was obvious, I had been given weeks of introduction to the concept
of ImmutableJS, and was learning as I was developing.
Immutable state
If anyone asked me, at any time of the day, if their state should be immutable, I would immediately tell them YES!. If they asked why, I wouldn’t be able to give them a more elaborate explanation than:
- Makes you less likely to mess up your data.
- Makes you feel more in control regarding flow of data.
But it begs to ask the question, how much do you have to gain, as a developer, by including something like ImmutableJS? My honest answer would still be a lot, but it would definitely depend on the project, your team and scope.
Closing statement
After the project was more or less finished, the team had a debriefing in order to figure out what went wrong, what worked well. Most of us agreed that perhaps ImmutableJS isn’t something we would use again, unless we saw a specific need for it. The library doesn’t offer something otherwise unattainable, because immutability can still be sustained with more native methods.
We did agree on that we would perhaps try lodash for our next project. Similar to how ImmutableJS let us write more concise code, we feel that lodash could provide the same experience, but without the incompatibility issues with external components/libraries.
Pros
- More control
- More convenience methods for manipulating arrays and objects.
Cons
- Lack of issues on StackOverflow, articles and other community related articles.
- Documentation (some methods lack examples)
- Incompatibilities with libraries/components expecting plain objects and arrays.
- Somewhat steep learning curve