I jumped in the Redux bandwagon after spending the decade before that either in jquery hell (or pre-jquery hell), and eventually Backbone, Angular, and React + Flux.

I've touched probably 200+ production frontend apps of various sizes by now, ranging from a couple of pages, going to tens of millions of lines of Javascript in a single monolith.

Your millage will vary and everyone hits different challenges in their career, but to me, the biggest issues when building apps was never building them from scratch or adding new features. It was always maintaining existing features. So I optimize everything I do for that, as I consider everything else completely trivial except for groundbreaking algorithms designed by PhDs (which is not me) and not worth thinking about.

I've spent years trying to nail down why these apps, no matter who works on them, always end up impossible to deal with. No matter how much time is spent trying to figure out the architecture, documentation and design, it always goes to hell given enough time.

To me (and its a totally personal analysis), it was always nailed down to figuring out: "Where the F* does this value come from" or "how do I follow what the hell this button does". It should be simple. I can use a debugger, obviously, but as requirements pile on, it invariably goes to hell.

Elm, to me, is the panacea of solutions here. A single atomic state, and a UX that is nothing more than a projection (or a map, if you prefer) of state to UX.

And to keep the UX "dumb", you then need to externalize all state and side effect logic.

Once you have that, you can reason about any bug without even looking at the code. Is the UX wrong? Was the state right? No? Did the event triggered right? yes? Well, the bug HAS to be in the update function. Boom done.

Now the question becomes, how do you reproduce this in JavaScript, which doesn't even have an approximation of algebraic effects, doesn't have immutable data structures, doesn't have a good way to play with the dom in a declarative way...

React + Redux with a few extras from the ecosystem provide that. Who cares about boilerplate, I get predictability. The more you abstract, the less predictable things get and bugs can come from anywhere.

Inevitably as the app grows, you need to add stuff and weave it in the existing features. The decoupling of State <--> Selector <--> Component <---> Action <---> Reducer has a very tightly defined set of semantics where even the most complex requirement fall neatly in these atoms (not quite as neatly as Elm when it comes to side effects, but it's as close as I've found for now).

Build an app some other way that does the -exact- same thing? You'll either end up with just as much code (oh, it won't be as repetitive and boring, but it will be there. I LOVE boring code), or you'll end up with something much more rigid that requires more compromises. There's a few alternatives that get close, but they usually do so by tightly coupling concerns and making it harder to figure out where the hell shit is happening.

The only obstacle is that the reasons behind "why" things are done this way is almost lost to most people working with Redux, in spite of Mark's best effort to prevent it from happening (there's only so much he can do short of brainwashing the planet). When the "why" gets lost, the community starts building things that neuter Redux, making it seemingly useless vs the alternatives.