Closed ghola closed 7 years ago
After some more reading and taking a better look at how Elm does it, i think understand why the model is being accessed in the saga. It's mainly for the lack of a better abstraction in the JS land. In Elm the model mutation and the Cmd triggering are both done in the update function and update has access to the model. I guess redux-saga was the most capable off the shelf tool that could be used here and the fact that it bears the 'saga' name should be ignored in this context since it's not really used like a proper saga.
@tomkis1 Am I on the correct path with this line of thinking? Thanks.
The original goal of the library was to reproduce the Elm architecture in JavaScript using redux
because of its similarities with Elm and excellent tooling. We thought that the Elm was doing things right.
If you have looked in the repo history, you'd find out that this was just a wrong approach, blindly copying the architecture over to JavaScript simply doesn't make sense because of the missing secret sauce (Elm compiler). That's why we gave up on redux-loop
approach and albeit me personally was always advocating the idea of declarative effects reduced in reducer among application state, I am not fan of this approach anymore.
Mixing potentially asynchronous workflow (effects) with synchronous state transitions (reducers) is simply a bad idea for various reasons
Redux (albeit never officially admitted) is heavily inspired by CQRS/ES/DDD, however there's one thing which Redux is missing, and these are Commands. People tend to perceive UI interaction events as Events in Event Sourcing context but this is simply wrong because UI interaction is more of command where action creator (or thunks or sagas) is command handler and command handler is allowed to emit multiple (not just single) events. Business logic in traditional CQRS/ES/DDD implementation lives in command handlers. In fact, it lives in root aggregates but it's still accessed through Commands not Events so that's why I think it's a good idea to use select
in Sagas.
So to follow on:
After some more reading and taking a better look at how Elm does it, i think understand why the model is being accessed in the saga. It's mainly for the lack of a better abstraction in the JS land. In Elm the model mutation and the Cmd triggering are both done in the update function and update has access to the model. I guess redux-saga was the most capable off the shelf tool that could be used here and the fact that it bears the 'saga' name should be ignored in this context since it's not really used like a proper saga.
I think most people are really missing the real benefit of redux-saga
which is implementing your domain logic and emitting more granular actions (events) which could even help with decoupling
I also raised an issue about improper explanation.
TLDR: I think Elm is doing it wrong by mixing Commands in Updaters, it should be separated and that's what now is happening in redux world (redux-saga / redux-observable...). I also think that using select
in Saga is not antipattern, I just think that people tend to perceive saga as "yet another side effect model" yet they don't realise that side effect in this terms means something completely different (see my gist - no side effects, yet so many side effects :-))
I have some experience with DDD and to some degree with CQRS too, although not with ES (i have not practiced ES but i do know the theory behind it). I also ported NServiceBus to PHP (phpservicebus/core) as there was no message bus in the PHP world that had transactional guarantees for messages (atm it's only used internally and has no docs, but time provided those will come too).
I only recently started to get an increased interest for front end technologies and Redux was attractive from the very beginning because it seemed to apply patterns that i was used to on the server side. Redux docs also confess having CQRS/ES as a source of inspiration (at the bottom of the Motivation page). But as i dived in, the concept of action seemed a very blurry one, because as you noticed it conflates two different concepts: Command and Event.
To further the confusion, DOM events were never separated from actions. Terminology in the Redux docs seems to interchangeably use action and event. So event could potentially have 3 meanings: DOM event, command and domain event.
The same happened when i started reading the docs of redux-elm (after having read the docs of elm itself), because the saga was used both as a "real saga" (pure state machine that models a long spanning business process, which seems ideal on the client side when dealing with async operations ... it normally listens to events and produces commands, but it's not limited to just this pattern) and also as a command handler (in which it's legitimate to load up the read or the write model). That's the actual reason for this thread ... i was reading the docs, and redux-saga pushed all the right buttons until it started to get confusing.
I tend to agree with you that it's incorrect for
people to perceive UI interaction events as Events in Event Sourcing
Even in an architecture that uses commands and events, DOM events need to be a separate breed of events and not be confused with normal domain events, let alone with commands. DOM events should produce commands which would then mutate the model and emit domain events which could be listened by other components via some bus (so when it comes to fractability, published domain events would be the way to communicate between components. It would be based on explicit subscriptions so that ANY component in the system could potentially subscribe/listen to the events produced by ANY other component).
But it may be that this approach seems right to me only because of my background and applying this type of thinking to the UI might not be the best approach at all. Actually the very fact that there is so much turmoil in the JS land is the direct proof that people are still frantically searching for solutions. That's why as a noob in this area, I prefer to stay on the sidelines and I'm mostly trying to understand and ask questions.
So far redux-elm has the approach that appeals to me the most, but it still has to produce answers to important questions/problems like: global message passing, inter component communication, ways to avoid data duplication (access global storage). Or at least these are the parts that i have yet to understand.
As i'm looking at section 2.3.1 of the documentation i can't help noticing this line:
To my understanding sagas should be state machines and as such they encapsulate their own state. The only data they get (which can contribute to it's state changes) is the one derived from the messages it receives. This is the way in NServiceBus sagas and also the recommended way in the redux-saga documentation. In fact i had to look pretty hard to find
select
in the redux-saga docs; it gets introduced at some point but never explained and the only place it actually gets explained is the API Reference section. One could say it's kind of hidden in the docs, and the note beneath it is a good explanation why.Getting back to the redux-elm docs example, it could be easily fixed if the RequestMore action dispatched from the view would carry the topic as payload.
Another option that just crossed my mind is that the example in the docs is intentionally done like that, in which case I'm wondering why.