New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux and it's relation to CQRS (and other things) #351

Closed
notahat opened this Issue Jul 28, 2015 · 16 comments

Comments

10 participants
@notahat

notahat commented Jul 28, 2015

Opening this issue to continue an interesting Twitter discussion, copied below for posterity:

Edygar de Lima ‏@edygarDeLima says:

@acdlite @dan_abramov Why is Flux so analogous to Command-Query Segregation Responsibility and yet have a so diverged terminology?

Dan Abramov ‏@dan_abramov says:

I'm also curious, maybe @fisherwebdev, @jingc can shed some light? @edygardelima @acdlite

Bill Fisher ‏@fisherwebdev says:

@dan_abramov @edygarDeLima @acdlite - @jingc has more context, but the origins of Flux were more about solving state mgmt not adopting CQRS.

Pete Yandell ‏@notahat says:

@fisherwebdev @dan_abramov @edygarDeLima @acdlite @jingc Apropos: I tried mashing ideas from Redux & CQRS: https://github.com/envato/zero-flux

Dan Abramov ‏@dan_abramov says:

@notahat @fisherwebdev @edygardelima @acdlite @jingc For me the biggest problem is lack of actions ("facts"). Hard to separate data domains.

Pete Yandell ‏@notahat says:

@dan_abramov @fisherwebdev @edygarDeLima @acdlite @jingc Yeah, "actions" are more like "events" from the event sourcing world...

Pete Yandell ‏@notahat says:

@dan_abramov @fisherwebdev @edygarDeLima @acdlite @jingc But event sourcing and CQRS can and often do go hand in hand.

@gaearon gaearon added the discussion label Jul 28, 2015

@notahat

This comment has been minimized.

notahat commented Jul 28, 2015

So event sourcing, if you haven't come across it before, treats everything that happens in your domain as an "event", records every event, and regards the events as the source-of-truth. All other data is just viewed as derived state, and should be able to be regenerated by replaying events.

There's a very strong analogy with Redux here, I think. Actions are events, and using pure reducer functions to change state guarantees that replaying the actions will get you back the same state.

Event sourcing and CQRS go hand in hand, but it is possible to do either one without the other. (Not all the leading proponent of event sourcing would agree with that statement, but that's another discussion.)

The long and the short of it is: I think there are interesting things to be learned from both CQRS and Event Sourcing, and they may help get clarity around some of the ideas in Redux.

I do find the language from CQRS clearer than that from Flux and Redux, but that's probably a matter of taste. I certainly think the word "Store" has become very overloaded in the Flux world though.

@notahat

This comment has been minimized.

notahat commented Jul 28, 2015

P.S. I might, when I get a moment, see if I can take my toy example and convert it to use serialisable actions. It shouldn't be hard, and will help get rid of some of the metaprogramming black magic under the hood.

@edygar

This comment has been minimized.

edygar commented Jul 28, 2015

+1

For any non-familiar to CQRS + Event-Source, here's a great resource for learning:
http://cqrs.nu/tutorial/cs/01-design

@notahat, I do agree with you:

there are interesting things to be learned from both CQRS and Event Sourcing […]
I do find the language from CQRS clearer than that from Flux and Redux[…]

IMHO, CQRS and Flux are very alike, diverging only in their terminology, while Event-Source is exactly what Redux DevTools implements.

@notahat

This comment has been minimized.

notahat commented Jul 29, 2015

I added a diagram that'll hopefully make what I was doing with my toy CQRS example a bit clearer: https://github.com/envato/zero-flux/blob/master/docs/zero-flux.pdf

@ghost

This comment has been minimized.

ghost commented Aug 4, 2015

While maybe not intentional, the "single store" in redux reminds me of a presentation by @gregoryyoung where he describes "Current State is a Left Fold of previous behaviors"

@gaearon Do you think there is a direct correlation between the Redux store and the ideas behind EventStore?

@sporto

This comment has been minimized.

sporto commented Aug 5, 2015

I do agree, in my experience using several Flux implementations, actions are just (events | signals | messages). I do think the name action is a poor choice as it implies something else (doing something).

Usually doing something in flux happens in an async action. Those would be better called commands probably.

@gaearon

This comment has been minimized.

Contributor

gaearon commented Aug 14, 2015

Closing, as this doesn't seem actionable.

@glenjamin

This comment has been minimized.

glenjamin commented Feb 3, 2016

Action creators are basically commands
Actions are basically events
Dispatch() is effectively a command bus
Stores are more-or-less view projections

Flux & Redux are IMO implementations of the general CQRS pattern / principle.

From previous discussions I've had, I think I recall the reason for fresh terminology is either

  1. The similarity was noticed later
  2. To avoid deterring devs with baggage from existing implementations / knowledge

As you said, the CQRS principle is often conflated with DDD / Event Sourcing etc - which I think can detract from the simple core idea.

@slorber

This comment has been minimized.

Contributor

slorber commented Feb 3, 2016

@glenjamin for me action creators should not be command. We leave in the frontend so basically there is no command, when user does some action in the UI it should rather be an event.

Backend concepts can't always strictly relate to frontend concepts, because backend receive user intent in an aynchronous fashion while front receives it synchronously, so indeed the things always happen in the past.

I don't think action creators are needed at all, particularly if you start using redux-saga. See how I replace an action creator here: http://stackoverflow.com/a/34623840/82609

redux-thunk:

    <div onClick={e => dispatch(actions.loadUserProfile(123)}>Robert</div>

    function loadUserProfile(userId) {
      return dispatch => fetch(`http://data.com/${userId}`)
        .then(res => res.json())
        .then(
          data => dispatch({ type: 'USER_PROFILE_LOADED', data }),
          err => dispatch({ type: 'USER_PROFILE_LOAD_FAILED', err })
        );
    }

redux-saga:

    <div onClick={e => dispatch({ type: 'USER_NAME_CLICKED', 123 })}>Robert</div>

    function* loadUserProfileSaga() {
      while(true) {
        const action = yield take("USER_NAME_CLICKED")
        const userId = action.payload;
        try {
          const userProfile = yield fetch('http://data.com/${userId}')
          yield put({ type: 'USER_PROFILE_LOADED', userProfile })
        } 
        catch(err) {
          yield put({ type: 'USER_PROFILE_LOAD_FAILED', err })
        }
      }
    }

Also just wrote a little bit about how Domain-Driven-Design (often used in backend with eventsourcing) can also be used in frontend. See https://github.com/rackt/redux/issues/1315#issuecomment-179164091

@tvedtorama

This comment has been minimized.

tvedtorama commented Oct 12, 2016

Hi, I think this is a very interesting topic! In my project I have used react-redux and thunks to create the front-end basics. I have long planned to use event-sourcing/CQRS on the server to handle, process and optimize data. In learning, and loving, Redux I realized that this will most likely be the perfect environments for processing the commands server-side and generate the checkpoints that the clients will see. The store will be mostly like a complex cache for the data store, loaded on demand. As commands come in, redux-sagas (or maybe thunks) will process them and send actions both to persistence (checkpoints) and the reducers. The clients will read the result of this after receiving RT-updates and refresh their redux-state correspondingly.

Does anyone have any experience with this, or any recommendations against it?

@sebas5384

This comment has been minimized.

sebas5384 commented Oct 14, 2016

@tvedtorama I agree with you, Redux can work in the backend/server-side even like a web server or your entire backend.
I'm working on some projects like redux-boot, redux-boot-webserver and as an example hades-server which demonstrates how you could build backend modules based on Redux API.

@slorber

This comment has been minimized.

Contributor

slorber commented Oct 14, 2016

Hey, if you want to use Redux for the backend, remember Redux is a very tiny library of only 70loc conceptually, and Redux concepts are largely inspired from existing backend stream processing systems.

Instead of porting back raw Redux to the backend, where most of the tooling (devtools/react-redux/reselect...) can't be used, and many required tooling is missing (log persistance, state indexation, snapshotting and persisted log replay), just to reuse these existing 70loc, why not leverage existing backend toolings that solved the problem even before Redux existed in the first place?

I'm thinking of very simple tools, like EventStore , which permit for a long time to persist a distributed event-log, and to build log projections (equivalent of Redux action reducers). As the projection can emit new events it can also act like a saga.

For more advanced usecases, many tools already exist as well, like Kafka, Samza, Storm...

Don't forget to look as domain driven design, as modeling your app with events may not be enough in most cases, and you should probably understand what is a bounded context is and also an aggregate root.

@zalmoxisus

This comment has been minimized.

zalmoxisus commented Oct 14, 2016

Just to add that actually devtools can be used on backend via sockets, here's an example.

@slorber

This comment has been minimized.

Contributor

slorber commented Oct 14, 2016

great @zalmoxisus :)

But not sure it's very useful for backend, I'll have to wait to see a real usage of that to be convinced :p. People building event-sourced apps usually replay the whole log after a reducer/projection change, and it's less likely the user use time travel in my opinion. Eventually it could help to reset given state to reproduce the context of a bug, but it's already what snapshots provide anyway :)

@tvedtorama

This comment has been minimized.

tvedtorama commented Oct 14, 2016

@slorber Thanks for the great feedback! I'll look into the server-targeted tools you mentioned. However, I think the ability to use the same frameworks on both front-end and server could be an advantage in itself, as this lessens the learning curve of the tool-stack. I even hope to reuse some of the reducers between the layers. DDD issues are definitely also valid concerns, and one should be careful not to just copy the structures of the front end. I was thinking to deal with bounded contexts either by simply defining parallel structures in the store - or parallel stores with different sagas / reducers altogether. These parallel structures would then partially respond to the same events, but calculate their state differently.

@sebas5384 Very interesting projects, I'll try to look into them in more depth when time permits.

@StevenACoffman

This comment has been minimized.

StevenACoffman commented Nov 4, 2016

@notahat Thanks very much! Do you have another copy of that diagram you created somewhere? That link appears to be dead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment