Hi,
in my regular boring corporate job I started with javascript + react-native + redux.
My bad feelings about javascript aside, I started using redux-saga (
https://github.com/redux-saga/redux-saga) and I like the approach, so I wanted to ask how feasible / valuable addition to StrangeIoC would be to add some of the concepts used in there.
Let me explain the concept...
Note: I don't like the term "saga", so I will call it "flow".
The basic idea behind flow is to merge together synchronous and asynchronous calls into more comprehensible structure - flow. Example:
Game Flow:
1/ load game level
2/ wait on LEVEL_LOADED
3/ init game
4/ start game
5/ wait on one of (GAME_FINISHED, GAME_ABORTED)
6/ if game is finished, save score
7/ go back to menu
In redux-saga this would translate 1:1 to something like:
function* gameFlow(){
yield call(loadGameLevelFlow); //calling subflow
yield take(LEVEL_LOADED); //wait for an event
yield call(initGame); //call subflow
yield call(startGame); //call subflow
let action = yield take([GAME_FINISHED, GAME_ABORTED]); //wait for one of the events
if (action.type === 'GAME_FINISHED'){
yield call(saveScore); //call some (synchronous?) service
}
yield put(SHOW_MENU); //dispatch an event
}
The beauty of this is, that you can express complex, asynchronous flows in a single function. You can nest these, wait for user input, etc.. and hide it behind a single line call.
Note that the flow can wait indefinetly for the events and the sub-flows might be also asynchronous and pause the wait.
There are more features than the mentioned call(), put(), take() (for example delay(), non-blocking calls, throttling (allowing subflow to be re-executed only after specific time)).
This is kinda like the Reactive approach, but in my opinion much more easier to understand.
As a side note, the flows in redux-saga do not actually execute anything by themselves, they just return a simple instruction object for each yield. The saga interpreter actually does the waiting, delays, etc.
This has a huge benefit you can unit-test the flows without any mocking neccessary. You just call .next() on the returned iterator and compare the instruction (e.g. test that now we should be waiting for the GAME_FINISHED event).
Also note that in redux you do not directly write into Model for some javascript concurrency reasons, so any modification of a model is also an instruction object.
Now the interesting part - introducing this to StrangeIoC ...
- The direct benefit would be to write "higher" level logic into single method and thus avoid the extra signal - command bindings overhead.
- You can replace the mentioned events with Signals 1:1 (at least with singletons, AFAIK)
- Flows would probably be the new thing since Commands are a different concept. Flows are not bound / executed by a signal as a rule, they are always called from another flow. In Redux-saga they allow this binding via a watcher flows like this:
function* gameFlowWatcher(){
yield takeEvery(START_GAME, gameFlow); //every time this event is dispatched, start game flow
}
function* gameFlow(){ ...}
But you can always replace direct sub-flow call via this indirection and vice versa - depending on which style you prefer.
What do you think? Is it worth considering?
I might try to implement it once I get some free time ...
Josef