These are chat archives for jdubray/sam

17th
Oct 2016
Charles Rector
@chuckrector
Oct 17 2016 04:34
hmm, i had seen the fishing game sample but only briefly. i will revisit and study it more closely now that i am starting to get more familiar
i made a v2 of my scene editor, which can add/remove/reorder sprites now http://codepen.io/chuckrector/pen/dpqYKv/
so far, i like that it has been straightforward to add new actions
for generating components, it's interesting how similar ES6 template strings can be to JSX
the main irritation so far is simply nesting of quotes
Charles Rector
@chuckrector
Oct 17 2016 04:43
i have noticed also that onclickevents etc cannot easily accept a variable for the event handler function, since you must explicitly emit the names of the functions to be called, e.g. onclick="actions.addSprite({})"
it makes me want to learn how JSX achieves onClick={addSprite} by a reference to the fn
fighting nested quotes puts an interesting pressure on the factoring of your components tho -- to avoid fighting that, i tend to simply break out that piece of component into its own component function
Charles Rector
@chuckrector
Oct 17 2016 04:49
until now, i was a bit confused on how the model would "accept" values. but then i wrote an addSprite action which proposes a name value in the new sprite -- in the model i do not accept the proposed sprite unless the trimmed name has a non-zero length. that seems to be a decent case for "rejecting" a proposal. i suppose validation in general is a use-case there. though i should do something interesting as a result in the ui, rather than "drop the proposal on the floor", such as show an error state in the ui indicating why the sprite was not added
i also didn't necessarily understand how an action would create some proposed values other than those passed directly to it from the call site of the action. but also in my addSprite action i only send the new name of the sprite and no other field values -- so, the addSprite action can fill in the blanks of the other missing fields and then propose that to the model. i could technically send all of those values from the call site, but then i suppose that's part of the value of the addSprite action -- it can have the knowledge of defaults in a central location, versus my duplicating all the defaults at all the call sites
Charles Rector
@chuckrector
Oct 17 2016 04:56
the actions for deleteSprite, reorderUpward, and reorderDownward turned out to be quite thin, as i only pass an id field for a given sprite
it's interesting that, in order for the model to know what to do with any presented data, it has to have some sort of "command" embedded in the presented data -- i suppose serving a similar function to, e.g., the type in the actions you pass to redux reducers
Charles Rector
@chuckrector
Oct 17 2016 05:01
for those thin actions, i suppose i could also technically just present some data directly to the model, since the actions all immediately present the passed in data to the model. but the "command" key is also added, so i suppose i see again how the purpose of the action is to centralize both the packaging of the data but also to know the appropriate command keys
just like in redux you can dispatch actions either by the "long-hand" store.dispatch({type: 'ADD_SPRITE', name: 'Knight'}) or instead make an "action creator" that adds the type for you, ala store.dispatch(addSprite({name: 'Knight'}))
Charles Rector
@chuckrector
Oct 17 2016 05:09
for v3 of my scene editor, i think it will be nice to simply drag sprites around rather than type their positions, which is quite cumbersome
Jean-Jacques Dubray
@jdubray
Oct 17 2016 06:18

i have noticed also that onclickevents etc cannot easily accept a variable for the event handler function

You can use "intents" to make it a bit simpler and more dynamic, especially when you use the dispatcher

Jean-Jacques Dubray
@jdubray
Oct 17 2016 06:24

For [instance]https://github.com/jdubray/sam-samples/blob/master/todomvc-app/mods/actions.js ):

actions.intents = {
    edit: 'actions.edit',
    save: 'actions.save',
    done: 'actions.done',
    displayAll: 'actions.displayAll',
    displayActive: 'actions.displayActive',
    displayCompleted: 'actions.displayCompleted',
    toggleAll: 'actions.toggleAll',
    delete: 'actions.delete'

} ;

and then:

onclick="return ${intents['done']}({'id':'${todo.id}'});">
JSX compiles it, they substitute the action label with the function call

I suppose validation in general is a use-case there.

there are two kinds of validation, first you need to validate the event, and its payload. That's the role of the action. The model should only be concerned with validating the integrity of the model (which should be hidden to the action). The action should only translate an event into a valid action. However there are (past) circumstances that may lead to reject the proposal. The action should have no way to know. But otherwise, yes, the model should validate if the proposed updates are acceptable and then substitute its property values with the proposed ones.

i should do something interesting as a result in the ui, rather than "drop the proposal on the floor"

you can do either. Please note that the action could also propose an "error value" if the event contained an invalid payload for instance.

Jean-Jacques Dubray
@jdubray
Oct 17 2016 06:30

how an action would create some proposed values other than those passed directly to it from the call site of the action

In the fishing game, I translate a "mouseDown" event to a "newRectangle" proposal. That's the kind of decoupling you want to achieve between the view and the model, because you might expand the game to work with something other than the mouse, so all you have to do is translate a new kind of event to a "newRectangle" proposal.

So you have to choose whether you label the action after an event or if you truly use an action verb

it has to have some sort of "command" embedded in the presented data

yes, it is generally true, though I use a dataset style so many actions could lead to triggering the same unit of work in the model. On the other hand you could also have one action that triggers multiple units of work in the model. This decoupling is important because otherwise the action would have to orchestrate triggering multiple units of work, this is undesirable. Your example is too simple to judge whether this is useful or not.

Jean-Jacques Dubray
@jdubray
Oct 17 2016 06:36

i suppose i could also technically just present some data directly to the model, since the actions all immediately present the passed in data to the model.

yes, in general the model should not have to "compute" property values. Collections are a bit harder to deal with, or "counters", any time you subtract or add then the model has to do some kind of computation. You cannot rely on the action proposing a complete collection or a counter+1 value for obviously concurrency issues.

The problem with Redux action creators is that they are dispatched from the point of initiation, when in SAM, an action is under full control (including with SAFE) as to whether it presents to the model or not. In particular, the action could present to more than one model, since SAM is based on a reactive loop, you have lots of flexibility on how the loop proceeds. Redux is extremely rigid from that perspective, for no value at all, simply because action creators are "hack" which fits a coercitive programming model .
Charles Rector
@chuckrector
Oct 17 2016 06:47

an action is under full control (including with SAFE) as to whether it presents to the model or not.

hmm, so like actions propose potential changes to the model, events "propose" potential actions. more generally, i guess the concept of a function is a proposal, as functions can run any conditional logic

hah, i never thought of it in that way before -- any function is not "do something" per se, but is always "maybe do something"
Charles Rector
@chuckrector
Oct 17 2016 06:53
since one of those somethings is always "no op"
Jean-Jacques Dubray
@jdubray
Oct 17 2016 07:01

any function is not "do something" per se, but is always "maybe do something"

yes, think of a glass of water, when you pour water, who decides the water level in the glass? the glass or the action of pouring? what if two people our water at the same time?

Yes, in particular the model can decide to do nothing.
This is the fundamental paradigm shift introduced by TLA+
In traditional state machine semantics (pretty much everyone think of it that way), the action decides the target state, you are in state 1 (S1), you perform action A and that leads to state 2 (S2).
What TLA+ says is that it does not work that way, that kind of behavior is an approximation.
An action propose values to the model, the model accepts or rejects these values (even partially) and it is the state function that decides which state (S2) you are in, based on the property values. Even when the model does not know which "state" the application is in.
The example I generally take is, think of a Tesla, what does it mean to "start" a Tesla?
Jean-Jacques Dubray
@jdubray
Oct 17 2016 07:07
The model knows the battery level and the destination. The car should be in "started" state only if the battery level allows you to reach your destination (including charging stations). Otherwise you are not in the "started" state. You are just in the "power on" state.
It makes no sense to "start" your trip if you cannot reach your destination. How would the "start" action know that? The only way to know it is to couple action, model and state. This is how we have been coding for decades.
Charles Rector
@chuckrector
Oct 17 2016 07:11
hmm, i think i see. so to mutate state without knowledge of control states is a sort of "blind" mutation. if you simply "force" into the start state, the result may be undesirable. whereas modeling according to proposals is always ensuring a correct model and thus a desirable future. or at least, within expectations and with less chance for surprises
Charles Rector
@chuckrector
Oct 17 2016 07:18
any model can always have flaws as designed by a human, but i suppose you're saying that without obeying control states, the train is immediately off the tracks you yourself have built (or intended to build, at any rate). that is, there are no checks and balances in a central location, therefore any step can easily be a misstep
Jean-Jacques Dubray
@jdubray
Oct 17 2016 08:51
@chuckrector yes, exactly, the code is easier to reason about, otherwise you end up orchestrating everyting from the action (the controller is MVC). Imagine, pure MVC the controller even selects the next view. It's bit like the action of pouring water in a glass decides if you are thirsty.

without obeying control states, the train is immediately off the tracks you yourself have built (or intended to build, at any rate). that is, there are no checks and balances in a central location, therefore any step can easily be a misstep

it's a bit more than that, the state is truly decoupled from the model. You could imagine different state function leaving off the same model (Web, Mobile, Watch) with different state representation and different allowed actions.

just figuring out the "allowed" action is a nightmare in traditional MVC (and recovering when you realize finally the action is not allowed). The RxJS camp recommends using subscribe/unsubscribe, that's a nightmare too.
Jean-Jacques Dubray
@jdubray
Oct 17 2016 08:58
SAM is just a factoring of the business logic, but it generally feels a bit more natural. Even something line nap() is a nightmare in Redux for instance, when with SAM it is a no brainer.
Last but not least, SAM is very easy to compose. You can compose 3rd party actions into your app, you can also easily compose SAM instances in parent/child relationships.