Well, most of my work is being the person who implements all these APIs you might be calling
So actually paying money is a very complicated process of quite a lot of business logic probably layered in more and more microservices.
I work in other (mutable) languages and attest to the opposite
My experience is that it’s one of the most pernacious cause of some of the most impactful issues, and hardest to root cause, and since I’m a DevOps, I feel the pain of that first hand at 3am. I also find it a leading issue when it comes to code structure, design and maintainability in a large code base with lots of engineers working on it over multiple years of time. The place-orientedness always seem to turn relatively new services into “legacy” on a “deprecation” path, because it gets too confusing to follow the data-flow as it is at runtime and make sure that the right thing will be in the right place at the right time and everything will be synchronized properly against it all.
It seems inscompicuous at first, until that one for-each-loop that mutate its own collection as it iterates, and does so from inside of a setter of a method that’s called from another layer which is passed the collection from inside the loop.
Or untill people start to “conveniently” modify what they need too in order to deliver their story and the behavior changes they’re wanting to make, but do so in an obtuse place down the call stack, which eventually becomes an unknown effect to anyone else working on the code base.
And so on…
The worst offender is really the simple case of passing a mutable thing to something else, that will unknowingly to the caller, mutate it, so that you’re assumptions of what you have after it returned are no-good, forcing you to take special care to drill-down into the call and validate yourself what is actually done to it almost every time.
But you’ve also got things like testing made so much easier with immutable data-structures. The simple act of having to reset the state after each test versus just passing the same immutable starting state to multiple tests, the latter is so much quicker.
And obviously if you throw in shared concurrent access, well that’s a whole other ballgame.
I’ve never really found mutable variants better unless I need performance to be honest. There’s a small argument to make about the use cases where the benefit is to modify a part of a larger thing in-place, such as Var redef being the magic trick of REPL hot-reload without having to reload everything, so those cases mutable is also useful. And I think this latter use-case might also apply a lot for UI, and why it generally relies on mutability, though FRP ideas are interesting.
But in general I find immutable much easier to reason, work with and maintain.
Edit: I want to add, I don’t think it’s the panacea of software maintainability and safety. I think it’s only one small thing in fact, in Clojure it combines with many other small things to create a whole bigger than each of its parts. Which is why I’m not super excited that JS is maybe getting some immutable data-structures. The way I see it, immutable is just slightly simpler than mutable and let’s you reason about things more independently and in smaller chunks. If you combine multiple things that are all slightly simpler and more independent and easier to reason about, eventually you get that the entire code base is a lot simpler, with better divide and conquer, composed of smaller pieces that you can independently reason about, and that’s when you start.to get really 10x multiplier in overall benefits. It’s also why I’m not one of those make everything final always Java person, because in Java that is just not enough to really end up having an impact, unless you also take multiple other measures along with it.