DEV Community

Cover image for Why Redux is still #1?
Johnny Jarecsni
Johnny Jarecsni

Posted on

Why Redux is still #1?

Intro

After a rather dull and uneventful period of Redux dominance in the UI application architecture land, there have been quite a few novel state management frameworks released over the past few years. Mobx, Recoil, Diffx, Svelte's own state management, etc. just to name a few.

They all seem to embrace the idea of mutable state, and they seem to allow much more flexible software design than Redux. In fact, Redux as a framework forces us to use some very questionable techniques and constructs. It uses actions instead of plain methods or functions (ok it's inherited from Flux), huge switch statements to match reducers with actions, sagas to handle asynchronous side effects.

Redux was created to tackle the problem of messy web applications with hard to reason about code, difficult to trace errors. However Redux, while it does solve those problems, it also violates almost all software design principles, results in brittle, boilerplatey, hard to maintain code.

The biggest issue with Redux that it transforms your business domain during the implementation into something very low level, technical (for an analogy think assembly language). In other words, the resulting code does not resemble your original problem domain at all. It is a pile of reducers and sagas, with no concepts, entities, encapsulation and abstraction or in general, any structure at all. It is very difficult and costly to introduce any major or cross cutting changes into a Redux application as that requires fine adjustments and changes in many moving parts (in this code everything is open and exposed, there are no clear boundaries, or encapsulation). Yes, you can make quick initial progress and demo stuff every two weeks, at the cost of longer term maintainability.

So if Redux has so many obvious problems, why is it still the king of state management frameworks? What stops people from migrating to lighter, more flexible and more efficient frameworks? There must be something that these newer frameworks are missing... After spending years trying to convince people about Mobx, then Svelte, I think I know the answer. Actually there are more than one reasons for this.

Code navigability, code organisation

If you compare a Redux based application with, say, a Mobx one, you will see that Redux has well defined locations for doing certain things, whereas Mobx is less explicit or opinionated. You can have more expectations about a Redux based project, like for instance if you look for an action fired in a component, you can be sure that there will be a reducer configured for that action, and maybe a saga as well. Even if one does not like the idea of reducers (and I for one certainly do not like it), they have to admit it does introduce a way of decoupling and and improves navigability. So I believe any successful attempts to dethrone Redux will have to offer a similar mechanism.

Developer Tool

This is huge. People want to see how the state is changing, clearly, action after action. This is a must. Let me put it bluntly, without a Redux like developer tool, no state management framework has a serious chance to be considered as a replacement for Redux. Luckily most frameworks do offer such a tool (I can only hope that someone makes one for Svelte - Svelte has a great state offering but sadly lacks in the tooling department.)

One more thing...

Besides these two points, which are fairly easy to tackle (watch this space for more articles on that), there is another, more subtle issue here.

Redux fits the present day Agile method quite well, it does not require ANY effort for an upfront design (in fact, there is no need for any design at all!). You can start "wiring in" your atomic little reducers, press a button, state changes, wonderful isn't it? Other frameworks tend to need some sort effort to map the domain to an object model, define some interactions, state transitions, etc. This does not quite play well with Agile's delivery centered approach that wants to see something moving and flashing at the first Show and Tell.

So, my other prediction is that any successful contender to replace Redux, will have to find a middle ground, where devs are able to put something in place quickly and also to evolve a design over time, in an Agile fashion, that will help with long term maintainability and will be less sensitive to change. Exactly how that could be done is not clear to me yet, but we can clearly see the two extremes: a functional approach leading to assembly language level decomposition with all its problems, and a purely OO approach requiring heavy upfront design, often leading to difficult to reason about custom solutions.

As usual, the ideal solution will be somewhere in the middle!

Top comments (8)

Collapse
 
phryneas profile image
Lenz Weber

Most of the "Redux problems" have been tackled back in 2019:

  • We do not recommend Redux saga except for the most complex asynchronous data workflows. Thunks are good enough for most stuff, especially since data fetching is taken care of RTK Query if you use the official Redux Toolkit. redux.js.org/style-guide/style-gui...
  • We do recommend to use the React-Redux hooks instead of connect as that makes working with Redux in React components a lot more easy, especially with TypeScript. redux.js.org/style-guide/style-gui...
  • We do recommend working with Redux Toolkit. This massively reduces the code you are writing further and helps avoid the most common mistakes. redux.js.org/style-guide/style-gui...
  • We recommend a "per-feature" file structure with single-file logic instead of splitting things up into action/reducers/constants files. redux.js.org/style-guide/style-gui...

Generally, a modern Redux project has probably 1/4 of the Redux-related code as it would have with old-style Vanilla Redux.

Give the official Redux Tutorial a try: redux.js.org/tutorials/essentials/...

Collapse
 
lexiebkm profile image
Alexander B.K.

RTK Query looks nice, I have read a bit of it in the tutorial and saw code defining Endpoints. Because I will be dealing with data fetching, this new thing will be helpful in using Redux for data fetching. I don't mind taking time in learning it as far as it will give me benefits instead of creating things manually using createSlice, createAsynctThunk, etc.

Collapse
 
jarecsni profile image
Johnny Jarecsni

Thanks Lenz, will check these out. To be fair, there is a reason why Redux and in general, the functional paradigm rule the business web application landscape. And it is because they lend itself more towards agile, fast paced delivery. There is a 'machinery' in place, which is like an architecture for the application, no need to design anything. The whole thing is about basically putting the atomic bits (actions, etc) in place to get stuff done.. In a way this is orthogonal or inverted compared to an object oriented approach. And I have to say, it might well be a reasonable way of doing things, given the environment and the requirements. My concerns still remain about such an approach though, especially around maintainability. It seems to me a rather one-way street, implement and forget. There's such a significant transformation between the domain concepts and the implementation layer which makes changes, especially crosscutting changes quite difficult. But maybe it is not such a big problem. Most often changes are small, and applications can and are simply rewritten if it's not economical to improve them.

Collapse
 
phryneas profile image
Lenz Weber

You might be misunderstanding Redux there.
The point of Redux is exactly to model your domain logic.

Actions should handle full "events" in your application - "setter"-style Actions were never the correct way of using Redux.
Quite the opposite, even OOP is too small.
When did an event in an appliaction realistically only impact a single object? Why should one object start modifying other objects, just to hide that fact?
You will see the same event-driven model that Redux is using in many other business-level concepts like domain events and event sourcing.

Thread Thread
 
jarecsni profile image
Johnny Jarecsni

Lenz, I have been thinking about the point around 'setter-style actions' and I have to admit I am a little unsure as to what you mean here. Are you suggesting to have actions with more coarse grained payloads that then get shifted in the redux state in one go, as opposed to having multiple actions with fine grained payloads? And how do you mean OOP is too 'small'? I think I agree with the point on objects modifying other objects not being great - as it leads to hard to follow and reason about graph of inter-dependencies. But I am not sure if that is what you mean when you talk about OO problems?

Thread Thread
 
jarecsni profile image
Johnny Jarecsni

I have found the explanation around the modeling actions as events in the style guide so that is clear now.

Thread Thread
 
phryneas profile image
Lenz Weber

As for the other side of it, "OOP being too small", that also plays into the "actions as events" thing - one action could modify five different objects held in five different reducers, without these five objects having any knowledge of each other or even the dispatching component having knowledge of them at all.
With Redux, you dispatch one event-action and all five change without the dispatching component even being aware of who exactly will change.
For OOP you have to know of all the "recipients" in your component and call some kind of change method on every single one of them.

Thread Thread
 
jarecsni profile image
Johnny Jarecsni

Yes I get that, and I do like this decoupling in Redux. But I disagree that OOP itself would lend itself towards tight coupling. Actually I have come up with a simple design in an example Svelte application to help solve this exact problem. Svelte stores would naturally lean towards a problem you describe, so I was thinking what could I do to avoid this (as this would clearly keep people with a Redux/functional background away from Svelte or any other similar solution). I realised that a simple event bus can neatly decouple action originators from action performers. To make sure things stay neat, action performers do not themselves post anything back on the bus, they are allowed to update the stores only. So there is a one directional flow here too: UI component triggers event on the bus -> event handlers handles event (async backend call, etc. etc.) -> updates store variables (side effect) -> UI is rerendered. I think that we should not 'ban' OOP entirely. OOP is a powerful way for modelling your business domain. I think if it is used in combination with FP we can have the best results. FP is great in a number of scenarios, but it is not a silver bullet and shines most in data transformation, processes etc. but not so much in data modelling. Hence my opinion around the problems in the reducer model, which does result in the domain model being represented as a set of functions which do make it difficult to reassemble a mental model by looking at the code.