
Redesigning Redux - ShMcK
https://medium.com/@ShMcK/redesigning-redux-b2baee8b8a38
======
tomelders
The strength of redux is that all your interactions with it are through
functions. Redux today is far better than the Redux of yesteryear thanks to
things like ReSelect, Thunks, Sagas, Higher Order Components etc. All these
things augment Redux, and they can do so because of Redux's open embrace of
the humble pure function.

Once you commit to a config based approach, you're basically closing the door
to a future you can't imagine yet. I'm so tired of this short-sighted
obsession with configuration some developers seem to have.

I think the author has a myopic vision for where Redux should go.

~~~
badestrand
> The strength of redux is that all your interactions with it are through
> functions

I think it's the other way around: The greatest weakness of Redux is that
(unnecessarily) message passing instead of function calls are used.

Why do a `store.dispatch({type: 'INCREMENT', value: 10})` when it could be a
`store.count.increment(10)`? In basically all cases every action is handled by
exactly one reducer so just let the reducer be an object with methods instead
of a big switch function operating on string constants.

~~~
zzzzzzzza
I missed the part where you explained why changing the reducer to an object
with methods would bring any benefits, or what's bad about message passing (it
seems to me off the top of my head that changing this would at the very least,
break redux observable as it currently works)

~~~
bpicolo
> to an object with methods would bring any benefits

It lets static typing do a lot more work for you when using Typescript/Flow.
Less to remember and less to break.

Message passing is a really useful _architectural_ choice because it lets you
do powerful global operations. It's a lot crummier on the development
ergonomics front.

~~~
mezzode
You can already write interfaces for your Redux actions in TypeScript to get
the benefits of static typing, so I'm not even sure that there would be an
appreciable improvement if Redux used methods instead.

------
woah
While Redux is great because it enforces a single source of truth, the whole
thing with "actions" and "reducers" in Redux is a huge source of boilerplate.
In almost every Redux project I have worked on, developers bring in some weird
scheme to reduce the boilerplate load of having to come up with a bunch of
events when all that anyone wants to do is call some functions.

The fact that Redux forces you to use events to modify the store is a useless
complication which has spawned reams and reams of crazy libraries like redux-
thunk, redux-saga, standard action formats, etc. The craziest thing yet is
Ducks: [https://medium.freecodecamp.org/scaling-your-redux-app-
with-...](https://medium.freecodecamp.org/scaling-your-redux-app-with-
ducks-6115955638be). This is a pattern which tries as hard as possible to make
using events not feel like using events, by tying each event intimately to its
listener.

This library is a step in the right direction, but wrapping Redux seems
unnecessary. Here's a similar approach in 100 LOC:
[https://github.com/didierfranc/react-
stateful](https://github.com/didierfranc/react-stateful)

~~~
kn8
I share this sentiment. I always felt like Redux had the right idea (single
store modified via actions), but the API was just making things unnecessarily
complicated causing people to either write lots of boilerplate or come up with
complicated workarounds.

Here's yet another similar approach, also in 100 LOC
[https://qubitproducts.github.io/tiny-
atom/](https://qubitproducts.github.io/tiny-atom/). Been using it for a year
in a few projects.

------
agentultra
> You don’t need to understand what a “comonad” is to use jQuery, and you
> shouldn’t necessarily need to comprehend functional composition to handle
> state management.

Is there a point to spreading this piece of sage FUD?

It should not be surprising that pure functions + immutable state results in
fewer errors.

The "pattern" Redux asks you to use prevents you from shooting your leg off.
If you've written a sizeable application that uses global, mutable state the
benefits of Redux shouldn't be surprising.

My only gripe with this eco-system is that it constantly comes up with new
names and concepts for things that already exist in the FP world. I agree that
the math jargon is off-putting but so is having a dozen words for the same
concept. I think the latter is worse.

The library described in the article feels less like an abstraction and more
like a shuffling around of syntax. Useful but misleading with a title like,
_Redesigning Redux_.

 _Update_ : s/grip/gripe

~~~
Waterluvian
Coming from no math background I LOVE functional programming and would love to
learn what words I'm using have existing math terms.

~~~
agentultra
A functional programming rosetta stone? Sounds challenging and interesting!

~~~
Waterluvian
Hah. I just meant maybe a blog post that maps the terms I use in JavaScript
land with math land. Ie. "it's not a reducer it's a functormonadicfoobar"

~~~
worg
[https://eloquentjavascript.net/3rd_edition/00_intro.html](https://eloquentjavascript.net/3rd_edition/00_intro.html)

Not exactly a blogpost but a nice reading, explains a lot of the functional
programming terms and their mathematical analogs.

edit: s/slang/terms

------
halayli
> Consider time_saved to represent the time you may have spent developing your
> own solution

Developing your own solution is one thing, and developing your own solution
that's as battle tested as a popular library is another.

Baking your own solution helps you understand the core problem that a library
you could have used tried to solve. But generally speaking developers that
tend to do that have difficulty learning top to bottom and favor bottom up
approach which leads them to developing things from scratch. That's just a
personal anecdote though.

There are cases were a developer has been using a library for a while and is
experienced enough to come up with better solution and cleaner APIs but I'd
argue that's not the common case.

Understanding other people's code/libraries is a skill worth mastering.

~~~
tomelders
As far as libraries generally go, Redux is tiny.

[https://github.com/reactjs/redux/tree/master/src](https://github.com/reactjs/redux/tree/master/src)

The largest and most important part is CreateStore, but at 250 lines long
(mainly comments), it's shockingly simple when you take a look at it.

------
kenforthewin
Is Redux too complex? That's the central argument this article makes but I
find it to be patently false. What drew me to redux was its simplicity:
Abramov said from the beginning that it's not anything you can't code
yourself, it just provides a thin framework around making changes to some base
state object. Its main strength (to me) is that it forces developers to think
about state changes as mutations rather than recreating a spaghetti state
machine oneself.

~~~
the_gipsy
It's too much boilerplate. In my current project, I have to describe one
action 7 times:

    
    
      1. The constant var `const ACTION_NAME = ...`
      2. The constant's value `... = Symbol('ACTION_NAME')`
      3. The "action creator" function `const doAction = arg => ...` (extra creativity to add a verb here?)
      4. The action creator's return struct: `... => ({ type: ACTION_NAME, payload: arg })`
      5. The reducer switch clause `case ACTION NAME:`
      6. The container action to callback mapping `onClickThing: dispatch(doAction(42))`
      7: The jsx/component calling the callback `onClick={onClickThing}`
    

compare that to The Elm Architecture, from which redux is inspired AFAIK. An
action only needs to be referenced in 3 places:

    
    
      1. The tag on the Msg type: `type Msg = ActionName arg | ...`
      2. The `case` pattern matcher in the update function
      3. The view sending said Msg/action

~~~
pault
It's just javascript... when I'm writing a redux-backed app I will often
abstract out commonly repeated patterns in action creators and reducers. Every
project is different so I just wait until things start looking predictable and
refactor. Not trying to be snarky, I just see this a lot at work; people seem
to be locked in to the patterns used in the redux documentation and never
attempt to rewrite it as they would any other part of their app. It's quite
simple (especially if you are using ES6 with its destructuring assignment) to
write a function that takes an action type and a function body that eliminates
most of the boilerplate.

~~~
the_gipsy
Actually, I agree with you and appreciate that redux doesn't force something
like a framework on you. You have choice of (non-)immutability, async
handling, organizing your code, or how to "wrap it up" like you suggest.

------
r00nb00m
Nothing on this project solves the real problems and introduces different
ones, like how to have a reducer respond to different actions. My quibble with
React is that when you get into moderately complicated forms, you start
sprinkling stuff all over the place to get the desired output. Take for
instance the most popular form library, redux-form. It's very heavy on it's
own way of doing things, and there's a lot of stuff you have to know about it
to be able to read into what the hell is going on, and it's hard to keep shit
in the same place. Reselect is also very heavy handed for what it does. I
NEVER needed anything like reselect before redux, and it kinda went alright!
In my experience, for any reasonable development with redux you have to
introduce: reselect, redux-form, thunk, some sort of immutability (immutable
or redux-orm), a sprinkle of compromises and plenty of boilerplate, or roll
your own magic util functions (i actually rolled my own very similar stuff to
rematch, for quick and dirty stuff). When you summarise all that, it's really
not that simple anymore! By the time you get through all of that, you might
aswell pick up angular with the added benefit of clearer best practices, nicer
dependency injection (oh, but react calls it context so it's cooler!),
familiarity and type safety.

It's kinda funny how redux succeeded with such heavy concepts, which is
normally not the case. This is still a mistery to me.

Oh and don't get me started on HOC. Want a tooltip over your component? Sure,
wrap it in tooltip HOC! Sooo much nicer than directives!

------
danpalmer
This looks nice, although in Redux's favour is a large ecosystem of libraries
that will work with it. This highlights a problem I still have with the JS
ecosystem, which is relatively tight coupling between libraries. Of course
many of these libraries could be glued together manually without too much
work, but with the rapidly changing ecosystem and APIs for interoperability
between libraries, and the obscurity of some of the libraries (Redux being a
good example), this is often just not practical.

Compare this to Elm and the Elm architecture, and it seems worlds apart.
Interoperability between libraries that all works in the same straightforward
way, checked by the compiler.

It feels like the JS community made a lot of good decisions for the right
reasons, but still ended up in a place that isn't great.

~~~
heygrady
Babel is both the driving force of innovation and the cause of much of the
fragmentation in JS. Babel allows you to use the latest language features and
target the oldest environments. The trouble is that there's not a "right way"
to package software to cover all of the deployment concerns. Code needs to
work on Node going back several versions as well as browsers going back
several versions. And for mobile/desktop websites, your code bundle size is
extremely important. Rollup and Webpack 4 go a long way towards making this
easier but it's nothing close to a "standard best way" to do it.

~~~
danpalmer
That's a good summary of the fragmentation and coupling in the build tools,
but there's also the libraries themselves - React, Redux, React-Router, React-
Router-Redux, etc etc.

------
wwqrd
Seems kind of like replacing common functional patterns with esoteric
configuration objects?

------
eropple
I've never really understood the point of redux-thunk. But, then, I also don't
use asynchronous actions _in my datastore_.

Asynchronous actions feel, to me, that they belong at the component layer
where niceties such as spinners are being rendered, and then the backing store
is updated with the results of the triggered action.

What drives people to put all of that into their store?

~~~
silversmith
Thunk is not about storing async state in the datastore, it's more akin to
multithreading in my opinion.

In backend, you might spin up a thread to do expensive operation like API
access, and that thread has it's own database connection, to read and persist
data.

With thunk, you dispatch a thunk-ed action to do expensive operation like
fetching data from backend, and that action has it's own access to redux in
form of `dispatch` / `getState` arguments.

In the end, my component calls `fetchData` function upon mounting. And the
logic dealing with making multiple requests due to paging, or re-trying on
errors then lives its own life inside a thunk action, independent from the
component that spawned it.

~~~
eropple
How do you test the code being run inside the Redux store? How do you mock
your API client?

~~~
silversmith
A thunk action `fetchData` would return a `(dispatch, getState) => {}`
function. You call that with `getState` that would return your fixtures, and
verify that `dispatch` gets called as expected. For API, I use jest and mock
out imported functions.

------
vanderZwan
> _Is Redux more performant? No. In fact, it gets slightly slower with each
> new action that must be handled._

This point is not revisited. What is the performance of Rematch in comparison
to Redux? I mean I guess it's more or less the same, since it's essentially
Redux with less boilerplate, but it would be nice to have an explicit answer
to this.

------
Longwelwind
Can someone explain to me why someone would choose Redux over something like
MobX ?

I feel like implements an action for each modification of state (or group of
modifications) requires a lot of boilerplate code. In MobX, you treat your
data tree as a separate entity, and simply modify it. The UI is automatically
updated whenever it needs to.

Mobx isn't bad performance-wise, I think, since it only re-renders the
components that are listening to the modified variables when a modification
occurs.

The only advantage I see is being able to rewind the state store, which can be
quite cool when debugging.

I have done some medium-sized application (only games), and I don't think I've
run into any performance or readability problem with MobX. I've never done web
apps with a team, though, but I don't think Redux would specially make it
easier to work with other programmers.

~~~
mikewhy
> The only advantage I see is being able to rewind the state store

Another big one is being able to restore the state. In Redux, it's just one
giant object that can be easily serialized and use in the future. With Mobx,
I'm guessing you have to write deserialize logic for your various classes.

------
chncdcksn
(To preface, I use React/Redux in all of my web applications. I think Redux is
great for managing state.)

One thing I’ve never quite understood about Redux is why we are dispatching
pure data instead of a function of state. This would remove the need for
reducers, since your action _is_ your reducer. Something like this...

[https://gist.github.com/anonymous/a5d741c5dec81be61e0aa70820...](https://gist.github.com/anonymous/a5d741c5dec81be61e0aa708200b53d1)

Would this come with any drawbacks? I could see a large application having
performance issues because of a large number of function allocations, but for
small applications I don’t see a downside, just a simpler API.

~~~
bpicolo
Now what you have is a global mutable state store instead of an "immutable"
state store, as everywhere can change anything and tracking down what code
does what is back to being nightmarish.

------
senoroink
This article resonated with me fairly well. As someone who has had an
extensive background in Rails and has more recently switched to 100%
javascript, this kind of pattern is what the community needs. There's
something to be said about getting up and running as quickly as possible. Sure
you can make the argument that not everyone's application is the same, but
there's a ton of similar patterns that would have been better suited to having
less mental gymnastics with a simple config while still leaving the door open
with FP for those that want to fine tune.

------
myguysi
Isn’t one of the points of redux to decouple actions from reducers? How would
you implement multiple reducers responding to a single action if your actions
are tied to a reducer with a namespace?

~~~
methyl
This can be done using Subscriptions [1].

I have another problem with this library, which is relying on singleton
pattern for communication. This way, you cannot have more than one rematch
instance in one application, which can be limiting. It also makes reasoning
more difficult.

[1]
[https://github.com/rematch/rematch/blob/master/plugins/subsc...](https://github.com/rematch/rematch/blob/master/plugins/subscriptions/README.md)

~~~
myguysi
Ahh thanks, I was lazy and didn’t go looking for an answer. Though this line
seems a bit odd..

> In this case, subscriptions avoid the need of coupling the auth model to the
> profile model. Profile simply listens to an action.

I guess it’s no different to using “vanilla” redux actions but because actions
contain the reducer namespace then it’s inherently coupled to another model
isn’t it?

------
heygrady
Rematch reminds me of Marty.js. I like some of the ideas about providing a
createStore wrapper that is more zero-config and using something like redux-
actions to make reducers simpler. I have been using my own wrapper around
sagas to allow for dispatching effects.

They lose me with their idea of "models" where I have a global dispatch that
can be extended, like dispatch.modelName.actionName. That's just old school
object-oriented thinking layered on top of redux's functional programming
ideals.

~~~
mpfundstein
whats the problem of mixing the good parts of OOP with the good parts of FP?

~~~
ballenf
The two are just so fundamentally different that you will usually end up with
a net negative taking two good things from both worlds. With the parent
comment, you lose a degree of composability of the functional world while not
gaining any degree of inheritability from OOP.

------
mplewis
This approach looks really similar to the VueX approach: synchronous reducers
are mutations, and async effects are actions. Can't wait to try this out in my
next React project.

------
pluto9
Nice. I've thought of some of these myself and implemented them as helper
functions, but there are some new ideas here I hadn't thought of. Not sure I'm
ready to port my project to a new library, but I may try some of these out
piecemeal.

------
davedx
I like it. Configuration should be just that. Interested to read other
opinions.

------
castlegloom
should have known it was a ploy for yet another library.

