Why is immutability so important (or needed) in JavaScript?

60,607

Solution 1

I have recently been researching the same topic. I'll do my best to answer your question(s) and try to share what I have learned so far.

The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?

Basically it comes down to the fact that immutability increases predictability, performance (indirectly) and allows for mutation tracking.

Predictability

Mutation hides change, which create (unexpected) side effects, which can cause nasty bugs. When you enforce immutability you can keep your application architecture and mental model simple, which makes it easier to reason about your application.

Performance

Even though adding values to an immutable Object means that a new instance needs to be created where existing values need to be copied and new values need to be added to the new Object which cost memory, immutable Objects can make use of structural sharing to reduce memory overhead.

All updates return new values, but internally structures are shared to drastically reduce memory usage (and GC thrashing). This means that if you append to a vector with 1000 elements, it does not actually create a new vector 1001-elements long. Most likely, internally only a few small objects are allocated.

You can read more about this here.

Mutation Tracking

Besides reduced memory usage, immutability allows you to optimize your application by making use of reference- and value equality. This makes it really easy to see if anything has changed. For example a state change in a react component. You can use shouldComponentUpdate to check if the state is identical by comparing state Objects and prevent unnecessary rendering. You can read more about this here.

Additional resources:

If I set say an array of objects with a value initially. I can't manipulate it. That's what immutability principle says, right?(Correct me if I am wrong). But, what if I have a new News object that has to be updated? In usual case, I could have just added the object to the array. How do I achieve in this case? Delete the store & recreate it? Isn't adding an object to the array a less expensive operation?

Yes this is correct. If you're confused on how to implement this in your application I would recommend you to look at how redux does this to get familiar with the core concepts, it helped me a lot.

I like to use Redux as an example because it embraces immutability. It has a single immutable state tree (referred to as store) where all state changes are explicit by dispatching actions which are processed by a reducer that accepts the previous state together with said actions (one at a time) and returns the next state of your application. You can read more about it's core principles here.

There is an excellent redux course on egghead.io where Dan Abramov, the author of redux, explains these principles as follows (I modified the code a bit to better fit the scenario):

import React from 'react';
import ReactDOM from 'react-dom';

// Reducer.
const news = (state=[], action) => {
  switch(action.type) {
    case 'ADD_NEWS_ITEM': {
      return [ ...state, action.newsItem ];
    }
    default: {
        return state;
    }
  }
};

// Store.
const createStore = (reducer) => {
  let state;
  let listeners = [];

  const subscribe = (listener) => {
    listeners.push(listener);

    return () => {
      listeners = listeners.filter(cb => cb !== listener);
    };
  };

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach( cb => cb() );
  };

  dispatch({});

  return { subscribe, getState, dispatch };
};

// Initialize store with reducer.
const store = createStore(news);

// Component.
const News = React.createClass({
  onAddNewsItem() {
    const { newsTitle } = this.refs;

    store.dispatch({
      type: 'ADD_NEWS_ITEM',
      newsItem: { title: newsTitle.value }
    });
  },

  render() {
    const { news } = this.props;

    return (
      <div>
        <input ref="newsTitle" />
        <button onClick={ this.onAddNewsItem }>add</button>
        <ul>
          { news.map( ({ title }) => <li>{ title }</li>) }
        </ul>
      </div>
    );
  }
});

// Handler that will execute when the store dispatches.
const render = () => {
  ReactDOM.render(
    <News news={ store.getState() } />,
    document.getElementById('news')
  );
};

// Entry point.
store.subscribe(render);
render();

Also, these videos demonstrate in further detail how to achieve immutability for:

Solution 2

A Contrarian View of Immutability

TL/DR: Immutability is more a fashion trend than a necessity in JavaScript. If you are using React it does provide a neat work-around to some confusing design choices in state management. However in most other situations it wont add enough value over the complexity it introduces, serving more to pad up a resume than to fulfill an actual client need.

Long answer: read below.

Why is immutability so important(or needed) in javascript?

Well, I'm glad you asked!

Some time ago a very talented guy called Dan Abramov wrote a javascript state management library called Redux which uses pure functions and immutability. He also made some really cool videos that made the idea really easy to understand (and sell).

The timing was perfect. The novelty of Angular was fading, and JavaScript world was ready to fixate on the latest thing that had the right degree of cool, and this library was not only innovative but slotted in perfectly with React which was being peddled by another Silicon Valley powerhouse.

Sad as it may be, fashions rule in the world of JavaScript. Now Abramov is being hailed as a demigod and all us mere mortals have to subject ourselves to the Dao of Immutability... Wether it makes sense or not.

What is wrong in mutating objects?

Nothing!

In fact programmers have been mutating objects for er... as long as there has been objects to mutate. 50+ years of application development in other words.

And why complicate things? When you have object cat and it dies, do you really need a second cat to track the change? Most people would just say cat.isDead = true and be done with it.

Doesn't (mutating objects) make things simple?

YES! .. Of course it does!

Specially in JavaScript, which in practice is most useful used for rendering a view of some state that is maintained elsewhere (like in a database).

What if I have a new News object that has to be updated? ... How do I achieve in this case? Delete the store & recreate it? Isn't adding an object to the array a less expensive operation?

Well, you can go the traditional approach and update the News object, so your in-memory representation of that object changes (and the view displayed to the user, or so one would hope)...

Or alternatively...

You can try the sexy FP/Immutability approach and add your changes to the News object to an array tracking every historical change so you can then iterate through the array and figure out what the correct state representation should be (phew!).

I am trying to learn what's right here. Please do enlighten me :)

Fashions come and go buddy. There are many ways to skin a cat.

I am sorry that you have to bear the confusion of a constantly changing set of programming paradigms. But hey, WELCOME TO THE CLUB!!

Now a couple of important points to remember with regards to Immutability, and you'll get these thrown at you with the feverish intensity that only naivety can muster.

1) Immutability is awesome for avoiding race conditions in multi-threaded environments.

Multi-threaded environments (like C++, Java and C#) are guilty of the practice of locking objects when more than one thread wants to change them. This is bad for performance, but better than the alternative of data corruption. And yet not as good as making everything immutable (Lord praise Haskell!).

BUT ALAS! In JavaScript you always operate on a single thread. Even web workers (each runs inside a separate context). So since you can't have a thread related race condition inside your execution context (all those lovely global variables and closures), the main point in favour of Immutability goes out the window.

(Having said that, there is an advantage to using pure functions in web workers, which is that you'll have no expectations about fiddling with objects on the main thread.)

2) Immutability can (somehow) avoid race conditions in the state of your app.

And here is the real crux of the matter, most (React) developers will tell you that Immutability and FP can somehow work this magic that allows the state of your application to become predictable.

Of course this doesn’t mean that you can avoid race conditions in the database, to pull that one off you’d have to coordinate all users in all browsers, and for that you’d need a back-end push technology like WebSockets (more on this below) that will broadcast changes to everyone running the app.

Nor does it mean that there is some inherent problem in JavaScript where your application state needs immutability in order to become predictable, any developer that has been coding front-end applications before React would tell you this.

This rather confusing claim simply means that if you use React your application is prone to race conditions, but that immutability allows you to take that pain away. Why? Because React is special.. its been designed first and foremost as a highly optimised rendering library with state management subverted to that aim, and thus component state is managed via an asynchronous chain of events (aka "one-way data binding") that optimize rendering but you have no control over and rely on you remembering not to mutate state directly...

Given this context, its easy to see how the need for immutability has little to do with JavaScript and a lot to do with React: if have a bunch of inter-dependent changes in your spanking new application and no easy way to figure out what your state is currently at, you are going to get confused, and thus it makes perfect sense to use immutability to track every historical change.

3) Race conditions are categorically bad.

Well, they might be if you are using React. But they are rare if you pick up a different framework.

Besides, you normally have far bigger problems to deal with… Problems like dependency hell. Like a bloated code-base. Like your CSS not getting loaded. Like a slow build process or being stuck to a monolithic back-end that makes iterating almost impossible. Like inexperienced devs not understanding whats going on and making a mess of things.

You know. Reality. But hey, who cares about that?

4) Immutability makes use of Reference Types to reduce the performance impact of tracking every state change.

Because seriously, if you are going to copy stuff every time your state changes, you better make sure you are smart about it.

5) Immutability allows you to UNDO stuff.

Because er.. this is the number one feature your project manager is going to ask for, right?

6) Immutable state has lots of cool potential in combination with WebSockets

Last but not least, the accumulation of state deltas makes a pretty compelling case in combination with WebSockets, which allows for an easy consumption of state as a flow of immutable events...

Once the penny drops on this concept (state being a flow of events -- rather than a crude set of records representing the latest view), the immutable world becomes a magical place to inhabit. A land of event-sourced wonder and possibility that transcends time itself. And when done right this can definitely make real-time apps easier to accomplish, you just broadcast the flow of events to everyone interested so they can build their own representation of the present and write back their own changes into the communal flow.

But at some point you wake up and realise that all that wonder and magic do not come for free. Unlike your eager colleagues, your stakeholders (yea, the people who pay you) care little about philosophy or fashion and a lot about the money they pay to build a product they can sell. And the bottom line is that its harder to code for immutability and easier to break it, plus there is little point having an immutable front-end if you don't have a back-end to support it. When (and if!) you finally convince your stakeholders that you should publish and consume events via a push techology like WebSockets, you find out what a pain it is to scale in production.


Now for some advice, should you choose to accept it.

A choice to write JavaScript using FP/Immutability is also a choice to make your application code-base larger, more complex and harder to manage. I would strongly argue for limiting this approach to your Redux reducers, unless you know what you are doing... And IF you are going to go ahead and use immutability regardless, then apply immutable state to your whole application stack, and not just the client-side, as you're missing the real value of it otherwise.

Now, if you are fortunate enough to be able to make choices in your work, then try and use your wisdom (or not) and do what's right by the person who is paying you. You can base this on your experience, on your gut, or whats going on around you (admittedly if everyone is using React/Redux then there a valid argument that it will be easier to find a resource to continue your work).. Alternatively, you can try either Resume Driven Development or Hype Driven Development approaches. They might be more your sort of thing.

In short, the thing to be said for immutability is that it will make you fashionable with your peers, at least until the next craze comes around, by which point you'll be glad to move on.


Now after this session of self-therapy I'd like to point out that I've added this as an article in my blog => Immutability in JavaScript: A Contrarian View. Feel free to reply in there if you have strong feelings you'd like to get off your chest too ;).

Solution 3

The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?

Actually, the opposite is true: mutability makes things more complicated, at least in the long run. Yes, it makes your initial coding easier because you can just change things wherever you want, but when your program goes bigger it becomes a problem – if a value changed, what changed it?

When you make everything immutable, it means data can't be changed by surprise any more. You know for certain that if you pass a value into a function, it can't be changed in that function.

Put simply: if you use immutable values, it makes it very easy to reason about your code: everyone gets a unique* copy of your data, so it can't futz with it and break other parts of your code. Imagine how much easier this makes working in a multi-threaded environment!

Note 1: There is a potential performance cost to immutability depending on what you're doing, but things like Immutable.js optimise as best they can.

Note 2: In the unlikely event you weren't sure, Immutable.js and ES6 const mean very different things.

In usual case, I could have just added the object to the array. How do I achieve in this case? Delete the store & recreate it? Isn't adding an object to the array a less expensive operation? PS: If the example is not the right way to explain immutability, please do let me know what's the right practical example.

Yes, your news example is perfectly good, and your reasoning is exactly right: you can't just amend your existing list, so you need to create a new one:

var originalItems = Immutable.List.of(1, 2, 3);
var newItems = originalItems.push(4, 5, 6);

Solution 4

Although the other answers are fine, to address your question about a practical use case (from the comments on the other answers) lets step outside your running code for a minute and look at the ubiquitous answer right under your nose: git. What would happen if every time you pushed a commit you overwrote the data in the repository?

Now we're in to one of the problems that immutable collections face: memory bloat. Git is smart enough to not simply make new copies of files every time you make a change, it simply keeps track of the diffs.

While I don't know much about the inner workings of git, I can only assume it uses a similar strategy to that of libraries you reference: structural sharing. Under the hood the libraries use tries or other trees to only track the nodes that are different.

This strategy is also reasonably performant for in-memory data structures as there are well-known tree-operation algorithms that operate in logarithmic time.

Another use case: say you want an undo button on your webapp. With immutable representations of your data, implementing such is relatively trivial. But if you rely on mutation, that means you have to worry about caching the state of the world and making atomic updates.

In short, there's a price to pay for immutability in runtime performance and the learning curve. But any experienced programmer will tell you that debugging time outweighs code-writing time by an order of magnitude. And the slight hit on runtime performance is likely outweighed by the state-related bugs your users don't have to endure.

Solution 5

The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?

About mutability

Nothing is wrong in mutability from technical point of view. It is fast, it is re-using the memory. Developers are use to it from the beginning (as I remember it). Problem exists in the use of mutability and troubles which this use can bring.

If object is not shared with anything, for example exists in the scope of the function and is not exposed to the outside, then it is hard to see benefits in immutability. Really in this case it is no sense to be immutable. The sense of immutability starts when something is shared.

Mutability headache

Mutable shared structure can easily create many pitfalls. Any change in any part of the code with access to the reference has impact to other parts with visibility of this reference. Such impact connects all parts together, even when they should not be aware of different modules. Mutation in one function can crash totally different part of the app. Such thing is a bad side effect.

Next often problem with mutation is corrupted state. Corrupted state can happen when mutation procedure fails in the middle, and some fields were modified and some not.

What’s more, with mutation it is hard to track the change. Simple reference check will not show the difference, to know what changed some deep check needs to be done. Also to monitor the change some observable pattern needs to be introduced.

Finally, mutation is reason of the trust deficit. How you can be sure that some structure has wanted value, if it can be mutated.

const car = { brand: 'Ferrari' };
doSomething(car);
console.log(car); // { brand: 'Fiat' }

As above example shows, passing mutable structure always can finish by having different structure. Function doSomething is mutating the attribute given from outside. No trust for the code, you really don't know what you have and what you will have. All these problems take place because: Mutable structures are representing pointers to the memory.

Immutability is about values

Immutability means that change is not done on the same object,structure, but change is represented in new one. And this is because reference represents value not only memory pointer. Every change creates new value and doesn't touch the old one. Such clear rules gives back the trust and code predictability. Functions are safe to use because instead of mutation, they deal with own versions with own values.

Using values instead of memory containers gives certainty that every object represents specific unchangeable value and it is safe to use it.

Immutable structures are representing values.

I am diving even more into the subject in medium article - https://medium.com/@macsikora/the-state-of-immutability-169d2cd11310

Share:
60,607

Related videos on Youtube

bozzmob
Author by

bozzmob

Simple living, High Thinking. Tech Enthusiast. I'm high on Javascript! Simply love Mozilla and Android.

Updated on July 08, 2022

Comments

  • bozzmob
    bozzmob almost 2 years

    I am currently working on React JS and React Native frameworks. On the half way road I came across Immutability or the Immutable-JS library, when I was reading about Facebook's Flux and Redux implementation.

    The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?

    Giving an example, let us consider a simple News reader app with the opening screen being a list view of news headlines.

    If I set say an array of objects with a value initially I can't manipulate it. That's what immutability principle says, right? (Correct me if I am wrong.) But, what if I have a new News object that has to be updated? In usual case, I could have just added the object to the array. How do I achieve in this case? Delete the store and recreate it? Isn't adding an object to the array a less expensive operation?

    • Mulan
      Mulan over 8 years
    • WorBlux
      WorBlux over 8 years
      Immutable data structure and pure function lead to referential transparency, making it a lot easier to reason about the behaviour of your program. You also get backtracking for free when using functional data structure.
    • prosti
      prosti over 7 years
      I provided a Redux point of view @bozzmob.
    • Gherman
      Gherman about 4 years
      It may be usefull to learn about immurability in general as a concept of functional paradigm instead of trying to think that JS has somehing to do with it. React is written by fans of functional programming. You have to know what they know to understand them.
    • Kristian Dupont
      Kristian Dupont almost 4 years
      It's not necessary, but it does offer some nice trade offs. Mutable State is to Software as Moving Parts are to Hardware
    • yiwen
      yiwen over 3 years
      Think from ReactJS point of view. How does it know you add an item if you return the same object with different content. You would have to tell it that the array has changed and a re-render is needed. What if in scenario some deeply nested data has been changed (recommend count, for example), the comparison would be slow because you need to traverse the whole array. But with Immutable principle, you have no choice but to return a new object. Now the react framework can easily know it needs to re-render by simply doing a pointer address comparison, which is super fast.
  • Mulan
    Mulan over 8 years
    I don't disagree with this answer but it doesn't address his "I'd like to learn from a practical example" part of the question. One could argue that a single reference to list of news headers being used in multiple areas is a good thing. "I only have to update the list once and everything referencing the news list gets updated for free" - I think a better answer would take a common problem like he presented, and show a valuable alternative that uses immutability.
  • Mulan
    Mulan over 8 years
    Up-vote for a generally good answer. However, carry your code example through. So addNews returns a new news array and the original news is untouched, but then what? Are you going to assign that to ... news2? And then the next call is news3? There seems to be an error in the approach for this specific bit of code. (Hint: does it make sense to use const for a state variable? State is specifically intended to change over time; I'd even say implicitly guaranteed)
  • danillouz
    danillouz over 8 years
    @naomik thanks for the feedback! My intention was to illustrate the concept and explicitly show that Objects are not being mutated and not necessarily to show how to implement it all the way. However, my example might be a bit confusing, I'll update it in a bit.
  • bozzmob
    bozzmob over 8 years
    A simple and great answer! Thanks @TwoStraws ... Just a quick question - Say now that I have to start using newItems in my program, should I clear the values in originalItems or will GC automatically take care of it? The thing is, if so many variables(objects I mean) are being created in the program, the memory usage will be too high right?
  • bozzmob
    bozzmob over 8 years
    @danillouz The reactjs example made things so much more clear. Thanks for such an informative and detailed answer. Just a quick question, Redux already use immutablejs right? If I start using redux, there is no need to require immutablejs. Am I right on this?
  • bozzmob
    bozzmob over 8 years
    A brilliant example I say. My understanding of immutability is more clear now. Thanks Jared. Actually, one of the implementations is UNDO button :D And you made things pretty simple for me.
  • TwoStraws
    TwoStraws over 8 years
    I'm glad the answer was helpful! Regarding your new question: don't try to out-guess the system :) In this exact case, something called "structural sharing" reduces GC thrashing dramatically – if you have 10,000 items in a list and add 10 more, I believe Immutable.js will try to re-use the previous structure as best it can. Let Immutable.js worry about memory and chances are you'll find it comes out better.
  • danillouz
    danillouz over 8 years
    @bozzmob you're welcome! No that is not correct, you need to enforce immutability in the reducer yourself. This means you can follow strategies like demonstrated in the videos or use a library like immutablejs. You can find more info here and here.
  • bozzmob
    bozzmob about 7 years
    @danillouz That surely helps. Predictable UI based on state was really a good point to mention. Thanks for the answer addition.
  • Lea Rosema
    Lea Rosema about 7 years
    @naomik ES6 const is not about immutability. Mathias Bynens wrote a great blog article about it.
  • Mulan
    Mulan about 7 years
    @terabaud thanks for sharing the link. I agree it's an important distinction. ^_^
  • Steven de Salas
    Steven de Salas about 7 years
    Imagine how much easier this makes working in a multi-threaded environment! -> Ok for other languages but this is not an advantage in single-threaded JavaScript.
  • Jared Smith
    Jared Smith about 7 years
    @StevendeSalas note that JavaScript is primarily asynchronous and event-driven. It's not at all immune to race conditions.
  • Steven de Salas
    Steven de Salas about 7 years
    @JaredSmith still my point remains. FP and Immutability are mighty useful paradigms to avoid data corruption and/or resource locks in multithreaded environments but not so in JavaScript because its single threaded. Unless I am missing some holy nugget of wisdom the main trade-off here is whether you are prepared to make you code more complex (and slower) in a quest to avoid race conditions ... which are far less of an issue than most people think.
  • bozzmob
    bozzmob about 7 years
    Hello Steven, Yes. I had all these doubts when I considered immutable.js and redux. But, your answer is amazing! It adds lot of value and thanks for addressing every single point that I had doubts on. It's so much more clear/better now even after working for months on immutable objects.
  • Steven de Salas
    Steven de Salas about 7 years
    Thanks! Really had to get that out out my system. I'm happy it came out in a constructive way ;)
  • rodrigo-silveira
    rodrigo-silveira about 7 years
    I think arr gets mutated every time you call fillWithZ
  • bedorlan
    bedorlan about 7 years
    if you use immutable.js, you will get a new copy of the object every time you change it. so the original object keeps untouched
  • Pavle Lekic
    Pavle Lekic almost 7 years
    I've been using React with Flux/Redux for over two years and I could't agree more with you, great response!
  • Pavle Lekic
    Pavle Lekic almost 7 years
    Please explain this "Mutation hides change, which create (unexpected) side effects, which can cause nasty bugs. When you enforce immutability you can keep your application architecture and mental model simple, which makes it easier to reason about your application." Because this is not true at all in the context of JavaScript.
  • Jared Smith
    Jared Smith almost 7 years
    I'm strongly suspicious that views on immutability correlate rather neatly to team and codebase sizes, and I don't think it's any coincidence that the main proponent is a silicon valley giant. That being said, I respectfully disagree: immutability is a useful discipline like not using goto is a useful discipline. Or unit testing. Or TDD. Or static type analysis. Doesn't mean you do them all the time, every time (although some do). I would also say that utility is orthogonal to hype: in a matrix of useful/superfluous and sexy/boring there are plenty of examples of each. "hyped" !== "bad"
  • Admin
    Admin over 6 years
    I think you make the same mistake as the immutability worshippers. Immutability makes some things easier but others more difficult. It is a trade-off and you have to check for each scenario individually whether it is worthwhile. Complexity may be abstracted, but it doesn't vanish into thin air.
  • Steven de Salas
    Steven de Salas over 6 years
    Hi @ftor, good point, taking things too far in the other direction. However since there is such a profusion of 'pro-immutability in javascript' articles and arguments out there, I felt I needed to balance things out. So newbies have an opposing point of view to help them make a judgement either way.
  • webketje
    webketje over 6 years
    Informative, and brilliantly titled. Until I found this answer, I thought I was the only one holding a similar view. I recognize the value of immutability, but what bothers me is that it's become such an all-other-technique-oppressing dogma (eg to the detriment of 2-way binding which is insanely useful for input formatting as implemented in KnockoutJS for example).
  • Steven de Salas
    Steven de Salas about 6 years
    @Tyblitz FYI for 2-way data binding VueJS is even more intuitive than Knockout, it uses getters/setters instead of observables.
  • Ski
    Ski almost 6 years
    I don't think Redux would make "undo" function that Project Manager might ask for any easier. Going back to previous state snapshot is only a little bit useful in development mode (though I'm yet to see anyone who would use this often in practice) but it's not useful to build anything else on top. You still need to coordinate undo updates with backend/database same way as you always used to do, plus state snapshot contains whole lot of things you might not want to recover.
  • Ski
    Ski almost 6 years
    Just because a pattern made sense in git does not mean same thing makes sense everywhere. In git you actually care about all history stored and you want to be able to merge different branches. In frontend you don't care about most of the state history and you don't need all this complexity.
  • Jared Smith
    Jared Smith almost 6 years
    @Ski it's only complex because it's not the default. I don't usually use mori or immutable.js in my projects: I'm always hesitant to take on third-party deps. But if that were the default (a la clojurescript) or at least had an opt-in native option, I'd use it all the time, because when I e.g. program in clojure I don't immediately stuff everything into atoms.
  • Steven de Salas
    Steven de Salas almost 6 years
    @Ski sure but bear in mind that if you are doing immutability right your back-end is also immutable and receives front-end updates (as a one way 'flow' of events), you'd be reversing changes in both the browser and the remote data store at the same time, and these would be cascaded through to all interested clients so everyone is in sync.. trying to coordinate two separate storage solutions for application state in front end and back-end is a bit of a nightmare... though a lot of people end up doing just that.
  • Ski
    Ski almost 6 years
    @StevendeSalas for synchronization you broadcast changefeeds. With redux you already got serializable actions, so you can broadcast that. Is it really that relevant if you write changes onto mutable or immutable structures?
  • Ski
    Ski almost 6 years
    How are you supposed to use same storage technique, if backend deals with whole dataset, possibly hundreds of gigs, while each client is only interested in subsets based on ACL and UI states (filters etc)
  • Steven de Salas
    Steven de Salas almost 6 years
    @Ski There are many ways to skin a cat here, but I would say that if you are doing immutability right your 'whole dataset' is actually the complete history of immutable events that affected your application state, and what you think of as your 'whole dataset' is actually a set of views/projections over the underlying immutable events that are indexed by object and show properties at the present time. As you mentioned, further subsets (filters) are views that narrow down those objects further and help users find what they are interested in. Hope this makes sense.
  • bozzmob
    bozzmob almost 6 years
    The 3rd paragraph makes so much sense. Thank you for that. 'If you want to "Undo" some state, you can create transactions'!!
  • Arshia001
    Arshia001 about 5 years
    Oh god, I love you so much for writing all of this.
  • Steven de Salas
    Steven de Salas about 5 years
    +1 I like it. Much more on point Jared. And yet immutability will not save a team from its own lack of discipline. 😉
  • Jared Smith
    Jared Smith about 5 years
    @StevendeSalas its a form of discipline. And as such, I think it's correlated with (but does not replace) the other forms of software engineering discipline. It complements, rather than supplants. But as I said in a comment on your answer, I'm not surprised at all that it's being pushed by a tech giant with a gaggle of engineers all grinding away on the same huge codebase :) they need all the discipline they can get. I for the most part don't mutate objects but also don't use any form of enforcement since, well, it's just me.
  • cdeszaq
    cdeszaq over 4 years
    You neglected to address perhaps the biggest aspect of what immutability brings to JavaScript-driven DOM control, and the foundation of what makes React so fast: awareness of change. For any non-trivial case, diffing two immutable structures is MUCH faster than knowing what changed in a mutable structure. Immutable structures only need to compute identity once and can cache the value for the entire sub-graph. (eg. Merkle Trees) A mutable structure, however, must traverse the entire graph every time, or contrive some other way to propagate change awareness.
  • ximo
    ximo over 4 years
    You're confusing "race condition" with "data race". While similar in some sense, they are not the same (see stackoverflow.com/a/18506177). Yes, single-threaded JavaScript does not have data races. But if you have concurrency and mutable state you may still experience race conditions. If you don't have concurrency, you don't need immutability. If you do have concurrency, immutability is an elegant solution to a complicated problem. When done correctly, using functional programming principles, I also think it makes code easier to reason about. But that is of course subjective.
  • ximo
    ximo over 4 years
    @StevendeSalas I agree that if you don't have a problem with race conditions, you'll do just fine without immutability. "If it ain't broke, don't fix it." You also say "don't believe the hype", which is another principle I agree with. But if you look beyond Redux and the hype train, immutability is a powerful concept that can radically improve the robustness of code. It does requires a different way of thinking about things, but if you deal with concurrency (the internet), I believe it's a tool that is well worth learning. I think Rich Hickey got a lot of things right in Clojure.
  • Steven de Salas
    Steven de Salas over 4 years
    @ximo completely agree on all counts. I would even say that if you dont have a problem with race conditions you'll do BETTER without immutability, unless there is some overriding architectural reason that justifies the additional expense and complexity (financial systems would do well to track every single transaction for example). I also agree that immutability brings benefits (mostly in simplified testing), however tradeoffs exist due to complexity, and the best situation is probably a combination of paradigms catering to the nature of the project, without dogma to fudge things up.
  • Steven de Salas
    Steven de Salas over 4 years
    Ximo, two words: "event-loop". If you understand how it works you'll also understand that JavaScript is single threaded and does not have race conditions inside the execution context. Concurrency issues DO occur however when you lose track of the order of execution. Which can happen due to the DESIGN CHOICES made in each framework. In this case React. Not to pop your balloon, but FP/immutability is there to make up for the design choices made in React state. I prefer better design, than finding an elegant solution to poor design.
  • ximo
    ximo over 4 years
    I find that FP with immutability can make code easier to follow and understand. But it depends on the use case, it's not always a good fit. Even Clojure admits that you do end up having to mutate state, and that you do need a "machine" around the functional bits. Luckily, it's not a binary choice! We can and should have a wide range of tools in our toolbox. A good programmer has a well equipped toolbox and knows when to use the right tool. There will always be a favorite though :)
  • ximo
    ximo over 4 years
    Joe Armstrong would say don't worry about performance, just wait a few years and Moore's law will take care of that for you.
  • ximo
    ximo over 4 years
    The comparison to Marxism can also be made for OOP, by the way. Remember Java? Heck, the odd bits of Java in JavaScript? Hype is never good, it causes radicalization and polarization. Historically, OOP was much more hyped than Facebook's hyping of Redux. Though they sure did try their best.
  • Jared Smith
    Jared Smith over 4 years
    @ximo Moore's law has run into some issues, not the least of which is that the world has moved to mobile which is more constrained by heat dissipation than transistors. That being said, JS is mostly IO bound anyway.
  • ximo
    ximo over 4 years
    @JaredSmith You're right, things are only getting smaller and more resource constrained. I'm not sure whether that will be the limiting factor for JavaScript though. We keep finding new ways to improve performance (Svelte for example). By the way, I completely agree with your other comment. The complexity or difficulty of using immutable data structures often comes down to the language not having built-in support for the concept. Clojure makes immutability simple because it is baked into the language, the whole language was designed around the idea.
  • Steven de Salas
    Steven de Salas about 4 years
    @cdeszaq, I have to disagree on the your claimed benefits of DOM control via immutability, re the awareness of change. You can easily construct a fast lookup tree structure by updating (mutating) each branch node with a re-calculated hash of its children array every time you change it and thus achieve the same result, in other words you don't need immutability to achieve a merkle tree... You either chose a bad example or cannot see beyond your favored technique.
  • cdeszaq
    cdeszaq about 4 years
    @StevendeSalas If you control access to the DOM tree, that is true. But if you allow for external modification of the tree, what ensures the hash gets updated up the tree? Preventing that, or rather controlling that, is what immutability provides for.
  • Syed Ali Taqi
    Syed Ali Taqi about 2 years
    one of the very best other side of the coin argument I ever read. you sir! deserve an applause.