These are chat archives for jdubray/sam

29th
Jun 2016
devin ivy
@devinivy
Jun 29 2016 02:33
@gunar i've been looking at sam-redux again recently. wondering about how you decided to implement certain things. model is the redux store. that makes good sense. i see nap() implemented by forming present as a call to the present logic (which may end in one or more dispatch() calls) followed by nap(). this isn't bad, but nap() only really needs to be called if the model changes, so i'd expect it to be wired by subscribing to the redux store.
devin ivy
@devinivy
Jun 29 2016 02:38
and the guts of present() really hide the dispatches to the store. what do you think of wiring present()as redux middleware that basically just forwards/reformats allowed actions coming from standard calls to dispatch()?
and the "state" is just a function of the model. i also like that. reselect seems like a good candidate for implementing that.
devin ivy
@devinivy
Jun 29 2016 02:56
so my thought for SAM-meets-traditional-redux would be,
  • model is a redux store.
  • actions are thunks.
  • nap() via model.subscribe().
  • present() is model.dispatch().
  • acceptor logic is redux middleware.
  • learners are implemented with ReactRedux.connect() and selectors (perhaps memoized with reselect).
Edward Mulraney
@edmulraney
Jun 29 2016 09:03
in redux actions are: dispatch(actionCreator(...))) in sam it's: model.present(intent(proposal))
the missing things in redux are control-state and acceptors. in redux there is no acceptor, or at least, it's automatically tied into the reducer. unit-of-work in sam == reducer
in sam the total "state" is model + control state. in redux you have to tie that into component logic somewhere
at least that's my understanding
Edward Mulraney
@edmulraney
Jun 29 2016 09:12
@devinivy from what I understand, you can do SAM in redux without having to expose anything "SAM-y" i.e. it appears the same to the developer - action creators, reducers, etc. but the internals wire it differently, as you say
Edward Mulraney
@edmulraney
Jun 29 2016 09:20
@jdubray it seems like a good idea to put the rendered component into the model as well. if I only mutate a part of the model relative to the feature currently in view, then I only need to rerender that part of the view. or conversely, if I mutate a model property associated with a feature not currently in view, I don't need to rerender the current view
Edward Mulraney
@edmulraney
Jun 29 2016 11:16
@jdubray i think the reason I found this pattern difficult to learn was because sam.js.org tries to define it in terms of State, Action and Model, but even now that I'm able to write apps in SAM and understand examples, this acronym is still not helping me. The acronym doesn't cover enough of the concepts in the pattern and that's why trying to define it by those three things makes it harder to learn. Also, the model definition is different to a model in MVC model. model = strate-tree. Really it would be something like CASPAINUP if you tried to get all the core concepts in, but it would probably be better to just call it something new entirely
Control-states, Actions, State-tree, Proposals, Acceptors, Intents, Next-action, Units-of-work, Present
Edward Mulraney
@edmulraney
Jun 29 2016 11:26
@devinivy i meant sam is model.present(proposal) and proposal = intent(event&|data)
devin ivy
@devinivy
Jun 29 2016 11:34
@edmulraney in redux i imagine the event being handed to an action creator (possibly a thunk) and the action-creator crafting proposals.
Edward Mulraney
@edmulraney
Jun 29 2016 11:34
yeah that's how i imagine it
devin ivy
@devinivy
Jun 29 2016 11:34
at the point that something gets "dispatched" to the store/model, it is a proper proposal
Edward Mulraney
@edmulraney
Jun 29 2016 11:35
i think the proposal is the data only. the dispatched proposal is an action. i could be wrong
{incrementBy: 1} vs dispatch({incrementBy: 1})
devin ivy
@devinivy
Jun 29 2016 11:35
this is where it becomes hard to talk about because redux and SAM use some similar terms differently :P
Edward Mulraney
@edmulraney
Jun 29 2016 11:36
very
devin ivy
@devinivy
Jun 29 2016 11:36
i appreciate what you're getting at there. my thought is that redux's store.dispatch() would receive actual proposals.
and those proposals would be made in what SAM would call actions, but what redux would call action-creators.
if you look at sam-redux you can see it works a little differently than that, which is why i bring it up.
Riccardo
@riccardoferretti
Jun 29 2016 11:39
+1 for CASPAINUP (just kidding ;) )
Edward Mulraney
@edmulraney
Jun 29 2016 11:39
:smile:
rolls off the tongue
@devinivy i've always thought the sam redux examples aren't quite doing it right
trying to implement concepts that already exist in redux but are named differently
devin ivy
@devinivy
Jun 29 2016 11:42
yeah it's hard! i might take a shot at forking sam-redux and seeing if i can make something that feels right.
i've grown to enjoy redux and its tooling fairly well, and SAM certainly has something to bring to the table. and i can see that SAM can definitely be implemented with redux (though i'd have to think quite a bit more about splitting client and server).
Edward Mulraney
@edmulraney
Jun 29 2016 11:46
i think when I first saw SAM i was keen to get the pattern working in redux. but i found as you start to do it, it makes a lot of redux redundant. the app i'm working on now basically feels like a redux app, but without the need for the eco-system. but i may change my mind again, i haven't finished this app yet
it would be cool to see your implementation tho, it seems we're thinking along the same lines
redux-router, redux-history, etc. are useful, and im not sure what we can use in a vanilla js app to achieve the same thing
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:08

@edmulraney

the rendered component into the model as well ... I mutate a model property associated with a feature not currently in view

I would argue that the State Representation is driven by the "State" and not the model. It would be a very bad idea to put this concern in the Model, that's why Model and State are completely separate.

Edward Mulraney
@edmulraney
Jun 29 2016 12:08
state is stored in model tho right?
Fred Daoud
@foxdonut
Jun 29 2016 12:09
@devinivy @edmulraney just in case you hadn't seen it already, here is a SAM/Redux example: http://codepen.io/foxdonut/pen/BzQzBx?editors=1010
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:09
The general idea is that actions should not make assumptions as to how the Model will do, and the model should not make any assumption as to how the State Representation will be computed.
The State function is optimizing the rendering by computing the current (control) state and from there deciding what's the best way to complete that task

state is stored in model tho right?

no, the model is a series of property values (a data structure) with minimal business logic that decides how these property values change

the application state is a combination of these property values and the state function. You cannot derive the application state from the property values alone.

The acronym doesn't cover enough of the concepts in the pattern and that's why trying to define it by those three things makes it harder to learn.

I'd argue this was the same for MVC (it was actually called ThingViewController pattern first.

I did ask for pal.js.org, but they have not responded yet. I'll try to follow up. I am not sure though Proposers, Acceptors, Learners will make it easier to grok the pattern better.
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:14
In Redux actions = proposals and action-creators = proposal creators (aka SAM Actions)
Edward Mulraney
@edmulraney
Jun 29 2016 12:16
PAL isnt any easier. I don't think an acronym is best way of conveying pattern
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:17
there are labels and then there are semantics ... Hopefully one day SAM/PAL could become a label on well understood semantics. I am not sure human languages derive semantics from labels (aka words), it's not necessarily fair to say that a TLA must convey enough semantics to be understood on its own
Routers and History are a kind of "actions" they put the application/system in a given state. The difficulty is to decide how you transition from the current application state to the route/history.
Fred Daoud
@foxdonut
Jun 29 2016 12:21
Besides everything you said JJ, I would add that (for me personally) when you said "Step", and "State Transition", that was [also] useful for me to understand the pattern.
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:22
And that's only scratching the surface of TLA+...
The way I see things evolving is more people incorporating additional TLA+ semantics in the way they write code.
SAM is just the beginning, kind of showing the way, but that's not the end of the story.
Edward Mulraney
@edmulraney
Jun 29 2016 12:24
@foxdonut step was also useful for me, when you break the step into parts, and show the order the step takes to complete
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:25
To go back to route/history:
  • history is like a pointer to an existing snapshot (you don't need to be able to recreate the application state from the path)
  • route is an action that is able to put the application state in a given state on its own
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:32

@foxdonut

"Step", and "State Transition"

At the same time, I am trying to not front load the pattern with a lot of concepts, because both step and state transition are optional

Edward Mulraney
@edmulraney
Jun 29 2016 12:32
@jdubray re: state. that's also how i understood it, which seems compatible with my idea. i would be storing the result of state(model). you have to have something like this otherwise we'll be rendering on page change when no mutation has occurred
youre just saying to not store it in the model, right?
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:33
it's more than "storing". First "State" is a function, it's not supposed to "store" anything
Edward Mulraney
@edmulraney
Jun 29 2016 12:33
state wouldn't store the value itself
the result of it would be stored somewhere
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:33
It returns the "allowed actions" to SAFE, but that's optional too
Edward Mulraney
@edmulraney
Jun 29 2016 12:33
i suggested model because you suggested earlier that everything should be in model
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:33
the State function compute the state representation
and triggers nap()
Edward Mulraney
@edmulraney
Jun 29 2016 12:34
yes, im suggesting storing this, rather than computing it on every load
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:34
then that's an optimization
Edward Mulraney
@edmulraney
Jun 29 2016 12:34
nap can be triggered after state function, doesn't have to be in it tho
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:34
which component will trigger it? it can't be the view/state representation
The State function is the best place because it computed the current state (in general)
the current state can be used for both
Edward Mulraney
@edmulraney
Jun 29 2016 12:35
as long as nap occurs after state function, its the same effect
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:36
We have to be very careful of the separation of concern
yes, of course
please note that something like the SAFE middleware could hold the rendering of the state representation until the nap actions has completed the next step
such that the view is rendered once
I just want to show that in general all these optimizations (including router/history) are relatively easy to position within the pattern
devin ivy
@devinivy
Jun 29 2016 12:37
@edmulraney have you used reselect with redux? it's perfect for computing control state, and it memoizes its results.
Edward Mulraney
@edmulraney
Jun 29 2016 12:38
if nap() is always called after state.representation(), then it doesn't make sense to force the developer to type this everytime at the bottom of their component code. im suggesting moving it out of there, so that it's just called automatically after state.representation()
removing boilerplate/repeated code
devin ivy
@devinivy
Jun 29 2016 12:38
"step" and "critical section" were terms that resonated with me when understanding SAM
@jdubray where does the state associated with each step live?
or is it outside of the model and we're okay with that?
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:40
@edmulraney all I am suggesting is that a responsibility of the "state" function and there could be many ways to implement it. calling nap is just one of them. Remember SAM is not a library/framework, nap is an essential part of SAM.
@devinivy "step" is optional, you rarely need it, but when you need it, it comes handy.
So far I have implemented that concept in SAFE, the pattern itself has no provision for enforcing steps.
It can only be done outside, in a middleware
I am expecting that if you provide the concept out-of-the box people will start finding lots of use for it
Edward Mulraney
@edmulraney
Jun 29 2016 12:44
@jdubray so to be clear: present(...) -> state(model) -> nap()
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:45
yes, but the State function may decide to implement the nap() as part of its own implementation.
Edward Mulraney
@edmulraney
Jun 29 2016 12:45
present(...) -> if model changed -> recompute state(model) -> nap()
present(...) -> if model unchanged -> return storedState -> nap()
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:45
The sequence is only logical
Edward Mulraney
@edmulraney
Jun 29 2016 12:45
cool - seems to fit with semantics :)
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:47
the State function may optimize in the following way:
if (countDown === 0) {
      stateRepresentation = 'launching...' ;
      actions.launch({launchParams: model.params}) ;
}
I don't want to make it "too formal" because it's not important, it's really the State function which is orchestrating the State Representation and NAP and it can decide the best way to do it, though logically, they are separate.
Edward Mulraney
@edmulraney
Jun 29 2016 12:48
whats the optimization?
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:48
The optimization is you don't have to test for countDown === 0 twice
Once you figure out the control state of the system, you can do whatever you want.
nap is going to work off the same conditions
Edward Mulraney
@edmulraney
Jun 29 2016 12:50
why would you need to test for countDown twice?
Jean-Jacques Dubray
@jdubray
Jun 29 2016 12:50
Both to create the state representation and in nap to decide what to do
As I mention before I don't want to make it look like a "state machine" because state machines are hard to code, if-then-else works great. SAM works well with both.
Edward Mulraney
@edmulraney
Jun 29 2016 12:57
im not sure what you mean by that really
state machines are hard to code in what way?
if then else works great in what way?
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:00
If you look at the rocket example you can see that there are some "state" conditions:
var _counting = (model: any) => {
        var status = ((model.counter <= model.COUNTER_MAX) && (model.counter >= 0) && model.started && !model.launched && !model.aborted) ;
        return status ;
    }

    var _launched = (model: any) => {
        return ((model.counter === 0) && model.started && model.launched && !model.aborted) ;
    }
Edward Mulraney
@edmulraney
Jun 29 2016 13:01
yes boolean statuses
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:01
it might be cumbersome to always reason as to what "control" state you are in.
You can just say "if counter === 0"
Edward Mulraney
@edmulraney
Jun 29 2016 13:01
vs state.launched ?
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:01
It's different than computing "readyToLaunch()"
I am really talking about computing the control state
state.launched has been computed
Edward Mulraney
@edmulraney
Jun 29 2016 13:02
a feature of the conrol state is that you no longer need to pollute other code with if-else conditional bloat
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:03
sure, but it's really up to you
sometimes it's too much overhead
Edward Mulraney
@edmulraney
Jun 29 2016 13:03
otherwise we might as well do away with control state and write if(counter ==0 )) eveyrwhere. that's bad
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:03
Some people may feel uncomfortable doing that way, while other people may find it natural
Edward Mulraney
@edmulraney
Jun 29 2016 13:04
its more about what's right vs what people like
otherwise they can stick with react-redux
since thats what they're comfortable with
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:04
well, it's a pattern, so I don't want to be too prescriptive.
I feel that if I put too much state machine semantics people will push back
at least initially until they feel comfortable with it
Edward Mulraney
@edmulraney
Jun 29 2016 13:05
i think its the other way round... unless you're targetting people who have only just started coding and who write if else for everything
myself and the other devs i know, would be put off of example code that contains tonnes of if else conditions. its a basic programming principle
but yes youre right, its up to the dev to write inline conditionals vs state.blah()
Edward Mulraney
@edmulraney
Jun 29 2016 13:12
but back to original question. is there anything wrong with storing the result of state.representation(model) in the model? and only re-computing it on model change
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:36
well, it's true that model+state() = application state
but I would prefer keeping them separate as a practice. I could see the case where the same model could have different state functions (learners)
Fred Daoud
@foxdonut
Jun 29 2016 13:45
Did you really mean state.representation(model)? I thought that was the view.
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:45
model is really about "units of work" / mutation / critical section
Note that you can use a strategy like Cerebral where you keep track of an "update summary" that you can pass to the state function
I don't there is there is just one approach to optimize the change detection mechanisms
Fred Daoud
@foxdonut
Jun 29 2016 13:47
if a certain state value is computed from the model, I don't see the gain of storing the result in the model. if it is for the convenience of the view, then that's a "view model" and yes I'd agree to store it in the "single application state tree", which is the model data.
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:47
state function -> what to display
view -> where to display
theme -> how to display
as long as you take these decision logically in context, then it's ok, from a general point of view, they are strictly separate. I don't think it would make sense to change that at the pattern level
Jean-Jacques Dubray
@jdubray
Jun 29 2016 13:57
In simple cases the state can take care of everything, view/theme are an optimization. What's important is to have the state function orchestrate the "learning" phase
Edward Mulraney
@edmulraney
Jun 29 2016 14:23
@foxdonut its not the control state value that I'd store - it's the rendered view. i suppose the benefit would be avoiding re-renders that you dont need to. altho i can't really think of that use case now..
Jean-Jacques Dubray
@jdubray
Jun 29 2016 14:23
in my code I pass "null" in the state representation when no re-rendering is necessary
I am a bit suspicious of black-box v-dom solutions
Fred Daoud
@foxdonut
Jun 29 2016 17:04
blob
Gang, thanks again for yesterday's discussion, I factored the changes (propose, receive, nextAction) into Meiosis.
Rocket Launcher example with React: http://codepen.io/foxdonut/pen/PzqOGG?editors=1010
Edward Mulraney
@edmulraney
Jun 29 2016 17:06
propose == present?
that does make more sense
oh wait no,i see receive is present
propose will be the action