These are chat archives for jdubray/sam

28th
Jun 2016
Fred Daoud
@foxdonut
Jun 28 2016 10:52
This message was deleted

Right now in Meiosis I have:

  • actions.sendUpdate(update)
  • receiveUpdate(model, update)
  • nextUpdate(model, update, actions)

I'm thinking of changing them to:

  • actions.trigger(action)
  • stateTransition(model, action)
  • nextAction(model, action, actions)

What do you think, people?

Edward Mulraney
@edmulraney
Jun 28 2016 13:51
without the context, i think that terminology is an improvement
I like the sound of Meiosis so far, I just want to get a better understanding of SAM before I try it out tho
Riccardo
@riccardoferretti
Jun 28 2016 14:10
agreed, hard to tell w/o more context. is actions.trigger(action) what you would call from e.g. the click handler? and in that call is action a fn or data?
Fred Daoud
@foxdonut
Jun 28 2016 14:11
Yes that is correct. action is data, the same data you would use in model.present(data)
Riccardo
@riccardoferretti
Jun 28 2016 14:11
also, not sure how receiveUpdate maps to stateTransition. I thought after the chat above that it would be called something like receiveProposal (and state transition would happen afterwards)
oh, so is trigger the action fn?
Fred Daoud
@foxdonut
Jun 28 2016 14:13
@riccardoferretti I know. I keep debating. If we have receiveProposal, then actions.trigger would be actions.sendProposal.
Riccardo
@riccardoferretti
Jun 28 2016 14:13
as in, you’d have actions.pour(data), actions.drink(data), ..
receiveProposal(model, actions.pour(data)) ?
Fred Daoud
@foxdonut
Jun 28 2016 14:14
I thought of actions.propose and accept, but as we said, accept might refuse.. I thought of consider, but that isn't intuitive
I was thinking stateTransition because that is what that function does, it receives the current model and the proposed action/change, and mutates the data, thus it is responsible for changing the state.
@riccardoferretti not quite. Let me give more context:
If you look at the section Update flow
Edward Mulraney
@edmulraney
Jun 28 2016 14:16
@foxdonut for accept/reject: handle()?
Fred Daoud
@foxdonut
Jun 28 2016 14:16
the view, event handler, etc. calls what is now actions.sendUpdate(data)
Meiosis wires things together so that what you specified as the receiveUpdate function, automatically gets called with the current model, and data
that function returns the new model (whether you mutate or not is up to you)
then the view gets refreshed, and finally nextUpdate gets called in case you want to trigger a nap()
Edward Mulraney
@edmulraney
Jun 28 2016 14:18
result of actions.propose(...) gets passed to model.present(...) right?
propose/trigger
Fred Daoud
@foxdonut
Jun 28 2016 14:18
@edmulraney yeah I thought of handle too, but that seems.. overused and vague
@edmulraney no, when you call actions.propose(data), it is data that gets passed to model.present(data)
Edward Mulraney
@edmulraney
Jun 28 2016 14:20
what does propose do?
Fred Daoud
@foxdonut
Jun 28 2016 14:20
it's how you trigger an action
it's the equivalent of model.present
Riccardo
@riccardoferretti
Jun 28 2016 14:21
who calls actions.propose?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:21
a sequence diagram would help
Fred Daoud
@foxdonut
Jun 28 2016 14:21
the diagram is there
in the link and section I indicated above.
Riccardo
@riccardoferretti
Jun 28 2016 14:21
so, it’s the handler that calls the propose?
in that case, the (e.g. dom) handler would be the action
in the SAM terminology
is that accurate?
Fred Daoud
@foxdonut
Jun 28 2016 14:22
blob
Riccardo
@riccardoferretti
Jun 28 2016 14:23
when a user clicks on a button, the handler for that event will perform some logic, then call actions.sendUpdate(data)?
Fred Daoud
@foxdonut
Jun 28 2016 14:23
correct
Riccardo
@riccardoferretti
Jun 28 2016 14:23
then I believe the handler is the action in SAM terms
in the case of the increment, the data you would send is
actions.sendUpdate({incrementBy: 1})
right?
Edward Mulraney
@edmulraney
Jun 28 2016 14:24
the action will be the mutation that occurs to the model if the proposal is accepted - the handler sends the intent
Riccardo
@riccardoferretti
Jun 28 2016 14:24
@edmulraney I agree
Fred Daoud
@foxdonut
Jun 28 2016 14:24
@riccardoferretti correct
yes
Riccardo
@riccardoferretti
Jun 28 2016 14:25
@foxdonut in that case see what @edmulraney said above :)
Fred Daoud
@foxdonut
Jun 28 2016 14:25
yes, as @jdubray it is also a state transition
Riccardo
@riccardoferretti
Jun 28 2016 14:25
feels like the handler should not call actions.sendUpdate({incrementBy: 1})
but should call actions.incrementCounter(), which would eventually call sendUpdate({incrementBy: 1})
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:26
@foxdonut if you plan to create a framework, I would definitely use a dispatcher as the event handler. One of the big value of SAM is the concept of "Step" and "allowed actions/proposals". Your framework should implement some of that like SAFE.
Fred Daoud
@foxdonut
Jun 28 2016 14:26
@riccardoferretti yes that is possible too.
@jdubray I agree :thumbsup:
Riccardo
@riccardoferretti
Jun 28 2016 14:28
right :)
Edward Mulraney
@edmulraney
Jun 28 2016 14:28
i think the separation of intent vs action makes things clearer
Riccardo
@riccardoferretti
Jun 28 2016 14:28
the dom handlers never really see sendUpdate, as their only interfaces with the system is actions.xyz
Fred Daoud
@foxdonut
Jun 28 2016 14:29
yes entirely possible
however
Riccardo
@riccardoferretti
Jun 28 2016 14:29
and the actions dictionary is the collection of available actions for a state
Fred Daoud
@foxdonut
Jun 28 2016 14:29
if sendUpdate is renamed trigger
you can still have actions.incrementCounter()
BUT
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:29
@riccardoferretti aboslutely, the view should have as little (ideally no) knowledge of the model
Fred Daoud
@foxdonut
Jun 28 2016 14:29
say you use UnionTypes
you might also have actions.trigger(Action.IncrementCounter())
there are different ways of encapsulating and hiding the details.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:30
the whole point of modern front-end architectures is to create a "component" model where the view components can be designed independently and mounted in the application.
This should be goal #1
Fred Daoud
@foxdonut
Jun 28 2016 14:30
both ways work nicely.
Right now I have sendUpdate, receiveUpdate, and nextUpdate, I'm not convinced
Riccardo
@riccardoferretti
Jun 28 2016 14:31
@foxdonut what’s the advantage of the latter?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:31

@foxdonut I don't like this much:

You can send whatever you want as an update. You may decide that you prefer sending an action as an update, such as a Flux Standard Action, that is, an object with a type and a payload

Riccardo
@riccardoferretti
Jun 28 2016 14:31
as in, it allows the user of the fwd to blur the line
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:31
a proposal is a proposal, not an "action", you have to pick semantics and labels (words), mix and matching is not helpul.
Fred Daoud
@foxdonut
Jun 28 2016 14:31
@riccardoferretti if you are using UnionType, your receiveUpdate is nicer
Riccardo
@riccardoferretti
Jun 28 2016 14:32
(which I am not sure would help deliver the semantics of the framework)
Fred Daoud
@foxdonut
Jun 28 2016 14:32
instead of if (data.editTodo !== undefined)
Riccardo
@riccardoferretti
Jun 28 2016 14:32
but if the goal is to cater to different semantics/opinions, I think that works
Fred Daoud
@foxdonut
Jun 28 2016 14:32
you'd have something like Action.case({ EditTodo: function(todo) {...} })
Riccardo
@riccardoferretti
Jun 28 2016 14:33
but you can still do that from within the action function
to simplify your receiveUpdate
Fred Daoud
@foxdonut
Jun 28 2016 14:33
no, I'm talking about the model accepting the proposal
personally I don't think presenting just data scales very well, model.present becomes messy very quickly.
Riccardo
@riccardoferretti
Jun 28 2016 14:34
yeah, you could have actions.increaseCounter() { …. receiveUpdate(Action.IncreaseBy(1))}
in the end, the action needs to talk to the model through a shared api, whether it’s a data structure or a union type
Fred Daoud
@foxdonut
Jun 28 2016 14:35
@jdubray a proposal is a proposal, yes. I can rephrase that better.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:35

model.present becomes messy very quickly.

not really if you think in terms of "units-of-work", it's ok to have the action suggest which unit of work to use, sometime you want a bit more loose coupling

Riccardo
@riccardoferretti
Jun 28 2016 14:35
to me that’s equivalent to actions.increaseCounter() { …. receiveUpdate({increaseBy: 1})}
Fred Daoud
@foxdonut
Jun 28 2016 14:35
BUT the proposal is NOT always of the same nature. Sometimes the data you propose is data that you just want the model to accept, and sometimes the data, like {incrementBy: 1} is... an action
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:36
@riccardoferretti yes, we have to accept that some proposal cannot be written in terms of value, but in terms of operation (I use operation instead of action)
Fred Daoud
@foxdonut
Jun 28 2016 14:36
@jdubray you say not to mix and match but you do it too :)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:36
@foxdonut NO, please, do not use the word action
Fred Daoud
@foxdonut
Jun 28 2016 14:36
operation
I like that
Riccardo
@riccardoferretti
Jun 28 2016 14:36
I like operation
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:36
An action creates a proposal to the model
Edward Mulraney
@edmulraney
Jun 28 2016 14:37
i thought that was an intent?
Fred Daoud
@foxdonut
Jun 28 2016 14:37
ok so then like I've asked before, what do you call what the action proposes to the model?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:37
For me event (click) -> intent (submit form) -> action (propose new address to the model)
the {incrementBy: 1} is an operation
Edward Mulraney
@edmulraney
Jun 28 2016 14:38
that's a proposal ?!
Riccardo
@riccardoferretti
Jun 28 2016 14:38
@foxdonut I would call it proposal
Fred Daoud
@foxdonut
Jun 28 2016 14:38
@jdubray so model.present(operation) ?
Edward Mulraney
@edmulraney
Jun 28 2016 14:38
a piece of data can't be an operation
Riccardo
@riccardoferretti
Jun 28 2016 14:38
an operation is a type of proposal
to address concurrency issues
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:38
That's really the problem that I am talking about, we have functions and data structures and we have to build precise semantics on top of that, we cannot say now a function is an action. An action here as a very precise meaning in the programming model, you cannot use an "action" anywhere else.
@riccardoferretti yes exactly
Riccardo
@riccardoferretti
Jun 28 2016 14:39
what would be the other type of proposal @jdubray
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:39
assignment
Riccardo
@riccardoferretti
Jun 28 2016 14:39
nice
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:39
sometime you still want an assignment even if you have concurrency issues
Riccardo
@riccardoferretti
Jun 28 2016 14:40
I was thinking e.g. if you have a reset button on the counter
you’d propose {counterValue: 0}
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:40
It's really the business logic which decides, but the programming model needs to give enough support to make it easy
@riccardoferretti yes, exactly
What I am saying is that the action may not know that the proposal is an assignment or an operation
only the model should decide because only the model should deal with concurrency (as a critical section).
Fred Daoud
@foxdonut
Jun 28 2016 14:42
so the data is a proposal
actions.trigger(proposal) ?
Riccardo
@riccardoferretti
Jun 28 2016 14:42
the data fed into the receiveUpdate fn
Edward Mulraney
@edmulraney
Jun 28 2016 14:42
ahh. you're not saying that the data structure {incrementBy: 1} is an operation, you're saying it's a proposal that leads to an operation, as opposed to a proposal which leads to an assignment {counter: 0}
Fred Daoud
@foxdonut
Jun 28 2016 14:43
receive(proposal)
Riccardo
@riccardoferretti
Jun 28 2016 14:43
sounds good
Fred Daoud
@foxdonut
Jun 28 2016 14:43
and nextAction
which may call actions.trigger(anotherProposal)
Riccardo
@riccardoferretti
Jun 28 2016 14:44
in your semantics of trigger, that’s correct
I personally am not sure if I like trigger inside actions
Fred Daoud
@foxdonut
Jun 28 2016 14:44
how do you mean?
Riccardo
@riccardoferretti
Jun 28 2016 14:45
just because I associate that to being an action then
that would be no different from actions.increment()
but actions.increment() -> Proposal
Fred Daoud
@foxdonut
Jun 28 2016 14:45
how about actions.propose(proposal)
Riccardo
@riccardoferretti
Jun 28 2016 14:45
so you could have actions.trigger(actions.increment())
Fred Daoud
@foxdonut
Jun 28 2016 14:46
that's not what I am going for.. if you have actions.increment() then you just call actions.increment() from the event handler.
Riccardo
@riccardoferretti
Jun 28 2016 14:46
but isn’t it model.propose(actions.increment())?
Fred Daoud
@foxdonut
Jun 28 2016 14:46
actions.increment() in turn calls actions.propose({incrementBy: 1})
Riccardo
@riccardoferretti
Jun 28 2016 14:46
yeah, because of the reactive style
but basically actions.propose is your exit point from actions
Edward Mulraney
@edmulraney
Jun 28 2016 14:47
that's where naming the action an intent makes it clearer I thought. you can intend to action a proposal, but you can't action an action
Riccardo
@riccardoferretti
Jun 28 2016 14:47
and I find it somewhat confusing that it lives next to them
Fred Daoud
@foxdonut
Jun 28 2016 14:47
hmm
Riccardo
@riccardoferretti
Jun 28 2016 14:47
basically, it’s a special action that shortcircuit having a function for an action
sorry, it’s not a “special action” - but it is a shortcut to proposing something without invoking an action
and yet it lives inside actions
that’s where my confusion comes from
Fred Daoud
@foxdonut
Jun 28 2016 14:48
ok so let's step back for a sec
in Meiosis, actions.propose(proposal) is your "entry point" to proposing something to the model
so instead of actions
what would you call it?
Edward Mulraney
@edmulraney
Jun 28 2016 14:49
intents
Riccardo
@riccardoferretti
Jun 28 2016 14:49
model.propose(proposal)?
Fred Daoud
@foxdonut
Jun 28 2016 14:50
because if you define increment() as encapsulating propose({incrementBy: 1})
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:50
@edmulraney an action is an intent to update the model
Fred Daoud
@foxdonut
Jun 28 2016 14:50
you'd call something.increment() from your event handler
something -> intents ?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:50
the action itself cannot update the model directly
Fred Daoud
@foxdonut
Jun 28 2016 14:50
no
Edward Mulraney
@edmulraney
Jun 28 2016 14:50
@jdubray what do you call the thing that mutates the model? model.counter + incrementBy. "learner"?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:50
The user has an intent which triggers an aciton
a mutation?
Fred Daoud
@foxdonut
Jun 28 2016 14:51
when you call something.propose(proposal) that just calls your receive(proposal) function, and that function actually decides if and what to do.
Riccardo
@riccardoferretti
Jun 28 2016 14:51
is it correct to say intent -> action -> proposal?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:51
yes, in general I would prefer that
Riccardo
@riccardoferretti
Jun 28 2016 14:52
if that’s correct, for me the intent is the onClick function associated to the dom node
Edward Mulraney
@edmulraney
Jun 28 2016 14:52
@jdubray is that addressed at me? you'd call the mutation the learner?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:52
@riccardoferretti yes, (user) intent -> action -> proposal
Riccardo
@riccardoferretti
Jun 28 2016 14:52
inside that function, you call the actions.increment()
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:52
@riccardoferretti yes
yes
Riccardo
@riccardoferretti
Jun 28 2016 14:52
inside the action, you call model.present(operation)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:52
yes
Riccardo
@riccardoferretti
Jun 28 2016 14:52
so, @foxdonut, having actions.propose(operation) is like doing intent -> propose
and especially the fact that it lives inside actions makes it confusing
Edward Mulraney
@edmulraney
Jun 28 2016 14:53
so they are intents until you wrap it with model.present
Riccardo
@riccardoferretti
Jun 28 2016 14:53
because it is basically the identity function
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:53
yes, some actions can be just the identity function, but I would argue this is rare
Riccardo
@riccardoferretti
Jun 28 2016 14:54
and even when that is the case, why not just wrap them into a function that conveys the meaning of the action
and keep a consistent api for the user
(user == developer using the fwk)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:54
yes, consistency is key, because if you need to add to biz logic then you'll be tempting to add it in the model rather than changing the type to a function
That's why I don't like the Redux model, because it gives just enough incentive to the developer to create spaghetti code on the reducer
Edward Mulraney
@edmulraney
Jun 28 2016 14:55
if you cleanly separate your code, you wont be putting model.present into your actions, you'd just be defining intents, which when triggered, get passed to model.present
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:56
Please understand that actions act as "adapters" between the view and the model
It is unlikely that the intent from the view component will be in the format that the model can understand
Riccardo
@riccardoferretti
Jun 28 2016 14:56
@edmulraney I think what you are calling intent is what we are calling operation?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:56
I am truly expecting that SAM will enable "themes" of view components to emerge and therefore they will be designed without the knowledge of specific models
Riccardo
@riccardoferretti
Jun 28 2016 14:56
and we call intent the function where the action is called from
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:57
You really have to keep that architecture in place, it is very very important
Fred Daoud
@foxdonut
Jun 28 2016 14:57
So actions.increment() calls propose(proposal) calls receive(model, proposal) ?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:57
This short cut has very negative consequences
@foxdonut that sounds one call to many
Edward Mulraney
@edmulraney
Jun 28 2016 14:58
@riccardoferretti im calling intent the function where the proposal is sent from
Riccardo
@riccardoferretti
Jun 28 2016 14:58
I see, we are calling that action
Fred Daoud
@foxdonut
Jun 28 2016 14:58
how do you mean @jdubray
Edward Mulraney
@edmulraney
Jun 28 2016 14:58
hmm
Jean-Jacques Dubray
@jdubray
Jun 28 2016 14:59
it is an action, anything that results in changing the model is an action
triggering an action is something different, it's best represented as an intent, if you need the distinction
Edward Mulraney
@edmulraney
Jun 28 2016 14:59
proposals: {incrementBy: 1}, {counterValue: 0}
intents: receiveEvent(eventData) returns proposal
actions: model.present({incremenBy: 1}), model.present({counterValue: 0})
Fred Daoud
@foxdonut
Jun 28 2016 15:00
I agree @edmulraney
intents: user clicks on +1 button -> onClick: function() {...}
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:00
Intents do not create proposal, they carry an event
like mouse position, user inputs,...
Edward Mulraney
@edmulraney
Jun 28 2016 15:01
that's just an event handler
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:01
Please be careful of semantics
Edward Mulraney
@edmulraney
Jun 28 2016 15:01
the intention is not the mouse click, but what the user wants to do (increment counter)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:01
You cannot have the same semantics at two different levels in the programming model
Edward Mulraney
@edmulraney
Jun 28 2016 15:01
the event handler HAS to carry the event
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:01
yes, but the only payload the intent can carry is the event
Riccardo
@riccardoferretti
Jun 28 2016 15:02
@foxdonut propose === curry(receive)(currentModel) - if that makes sense
(from your msg above)
but I think we are on the same page on the intent @edmulraney @jdubray
intents: user clicks on +1 button -> onClick: function() {...}
Edward Mulraney
@edmulraney
Jun 28 2016 15:04
yeah that fits
Riccardo
@riccardoferretti
Jun 28 2016 15:04
then, inside that fn, you would call the action - e.g. actions.increment()
so, intent -> action
the action prepares the operation proposal (e.g. {incrementBy:1} or {counterValue: 0}), and presents it to the model
Edward Mulraney
@edmulraney
Jun 28 2016 15:05
what would actions.increment() do*?
Riccardo
@riccardoferretti
Jun 28 2016 15:05
nothing, in this reactive loop
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:06
nothing is ever return, yes it is a reactive loop
Edward Mulraney
@edmulraney
Jun 28 2016 15:06
correction - return/do
Riccardo
@riccardoferretti
Jun 28 2016 15:06
once the proposal is ready, the action will call the model with it
Edward Mulraney
@edmulraney
Jun 28 2016 15:06
awesome. we have the same understanding
Riccardo
@riccardoferretti
Jun 28 2016 15:06
model.present(operation)
Fred Daoud
@foxdonut
Jun 28 2016 15:06
@jdubray I understand but propose(proposal) doesn't only call receive, meiosis also re-renders the view and calls nextAction, as you said, it takes care of the reactive loop.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:08
yes
Edward Mulraney
@edmulraney
Jun 28 2016 15:08
then the next part is: mode.present(operationProposal) receives the proposal, and has to handle it: if(proposal.incrementBy) { model.counter += proposal.incrementBy }
Riccardo
@riccardoferretti
Jun 28 2016 15:08
correct
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:08
yes, that's how it works
Edward Mulraney
@edmulraney
Jun 28 2016 15:09
what do you name this part: if(proposal.incrementBy) { model.counter += proposal.incrementBy } - the "learner"?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:09
unit-of-work
this is implemented by the acceptor
Edward Mulraney
@edmulraney
Jun 28 2016 15:09
unit-of-work is a type of action ?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:09
not the learner, the learner will then be able to access the new application state once the model says it's ok
noooo
Edward Mulraney
@edmulraney
Jun 28 2016 15:09
good :)
Riccardo
@riccardoferretti
Jun 28 2016 15:09
haha
Edward Mulraney
@edmulraney
Jun 28 2016 15:10
is unit-of-work the only CS term for this? I've only seen that used in DB transaction stuff
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:10
Not all semantics can be defined by "IS-A" relationships
Edward Mulraney
@edmulraney
Jun 28 2016 15:10
how would you define unit-of-work
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:11
semantics = IS-A + (HAS-A)+(Action)+(State)*
Edward Mulraney
@edmulraney
Jun 28 2016 15:11
purely a model mutation?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:11
aka STAR
yes pure model mutation, the whole point of SAM (and TLA+) is to surface the way you should mutate application state
Of course you cannot write every line of code like that
Riccardo
@riccardoferretti
Jun 28 2016 15:12

semantics = IS-A + (HAS-A)+(Actions)+(States)*

can you expand on that?

Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:12
So you have have to pick what you want to control from a mutation point of view
Edward Mulraney
@edmulraney
Jun 28 2016 15:12
this is good. it's quite easy to make a convention/blueprint for developing apps from these terms
Riccardo
@riccardoferretti
Jun 28 2016 15:12
(I don’t know how to read that formula)
Fred Daoud
@foxdonut
Jun 28 2016 15:13
Meiosis.createComponent({
  initialModel: { counter: 0 },
  actions: function(propose) {
    return {
      increment: function() {
        propose({ incrementBy: 1 });
      },
      decrement: function() {
        propose({ incrementBy: -1 });
      },
    }
  },
  receive: function(model, proposal) {
    model.counter = model.counter + proposal.incrementBy;
    return model;
  },
  view: function(model, actions) {
    var onIncrement = function(_evt) {
      actions.increment();
    };
    var onDecrement = function(_evt) {
      actions.decrement();
    };
    return (
      <div>
        Counter: {model.counter}
        <button onClick={onIncrement}> + </button>
        <button onClick={onDecrement}> - </button>
      </div>
    );
  }
});
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:13
semantics are a combinations of "relationships" (IS-A) and (HAS-A), sometimes, you need more too, such as some objects have specific actions and states, but that tend to be too specialized
The formula helps you understand that two concepts are distinct
Riccardo
@riccardoferretti
Jun 28 2016 15:14
@foxdonut where is the connection between receive and propose?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:14
if they have a different set of relationships, action, state, they are not the same
Fred Daoud
@foxdonut
Jun 28 2016 15:15
@riccardoferretti Meiosis passes you propose to actions: function(propose)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:15
properties of an object are generally not enough to distinguish semantics (like the color of a car, another color, doesn't change the semantics of the car)
Riccardo
@riccardoferretti
Jun 28 2016 15:15
right, but would it be wired with its own receive?
Fred Daoud
@foxdonut
Jun 28 2016 15:15
yes
Riccardo
@riccardoferretti
Jun 28 2016 15:15
oh ok
cool
Fred Daoud
@foxdonut
Jun 28 2016 15:16
then it automatically calls view
Riccardo
@riccardoferretti
Jun 28 2016 15:16
that snippet matches my understanding of SAM
nap?
Fred Daoud
@foxdonut
Jun 28 2016 15:16
yes. finally you could have nextAction: function(model, proposal, actions)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:17
yes, it's pretty close (nap, theme, intents) are missing
Edward Mulraney
@edmulraney
Jun 28 2016 15:17
@foxdonut @riccardoferretti agreed
Fred Daoud
@foxdonut
Jun 28 2016 15:17
nap() is not missing, you can add it as nextAction
Riccardo
@riccardoferretti
Jun 28 2016 15:17
intents are the onIncrement and onDecrement fns
devin ivy
@devinivy
Jun 28 2016 15:17
the only thing i'm unsure of is the implicit coupling between model, actions, views, etc.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:17
I meant from the sample
devin ivy
@devinivy
Jun 28 2016 15:17
just by all being in one "component"
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:18
I'd call it an "instance" rather than a component
Fred Daoud
@foxdonut
Jun 28 2016 15:18
@devinivy you can create multiple components
each one focusing on its own concern
Edward Mulraney
@edmulraney
Jun 28 2016 15:18
yeah the intents are onIncrement/onDecrement in my understanding
Fred Daoud
@foxdonut
Jun 28 2016 15:18
right @edmulraney intents are already there
devin ivy
@devinivy
Jun 28 2016 15:18
i understand that– but if i have two components there better be a really good reason the view is tied to that piece of state.
Fred Daoud
@foxdonut
Jun 28 2016 15:19
how do you mean @devinivy ? the view renders the model.
devin ivy
@devinivy
Jun 28 2016 15:19
it's not awful, i just think it could be abused very easily.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:19
@foxdonut no, this is not how it would work
blob
devin ivy
@devinivy
Jun 28 2016 15:19
@foxdonut i think the name "component" is what messes me up.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:19
The SAM instance is more an assembly
of loosely coupled components
devin ivy
@devinivy
Jun 28 2016 15:20
that "component" would have to be a self-contained SAM app for it to be kosher.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:20
you can also have a parent/child relationship between instance
Edward Mulraney
@edmulraney
Jun 28 2016 15:20
@jdubray @foxdonut that's the only thing i've done differently in my examples. my component is a component with no properties that directly state the coupling. it's all decoupled and then linked up outside
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:20
but SAM is designed to "assemble" components such as theme(s), action(s), ...
Also SAM's component can span tiers -> isomorphic javascript
I have shown that you can be isomorphic by design
Fred Daoud
@foxdonut
Jun 28 2016 15:21
@foxdonut no, this is not how it would work
@jdubray could you be more specific
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:22
I like the general API that you came up with, but for me it should be an "assembly", an app could be lots of components, built by many different people, even 3rd parties.
Fred Daoud
@foxdonut
Jun 28 2016 15:22
@edmulraney @devinivy @jdubray that is all possible.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 15:23
Now that we agree on the semantics, you should bring enough flexibility to create these assemblies
Fred Daoud
@foxdonut
Jun 28 2016 15:24
but for me it should be an "assembly", an app could be lots of components, built by many different people, even 3rd parties.
you could say that about every single simple example out there ;)
just because you show a simple example, not to overwhelm at first sight, doesn't mean you can't build more complex apps with more components.
Edward Mulraney
@edmulraney
Jun 28 2016 15:25
yes i can see how they would all tie together to create an app
Fred Daoud
@foxdonut
Jun 28 2016 15:25
this is flexible enough to create assemblies of components. Meiosis.createComponent returns V = f(M) which you can then use in other components' view to use them.
Edward Mulraney
@edmulraney
Jun 28 2016 15:25
i've built a similar thing
i need to do NAP
what is this defined as?
header, main, and footer are components
Edward Mulraney
@edmulraney
Jun 28 2016 15:27
yeah nice
i'm developing components in a way that allow you to not depend on the shape of the model, i.e. you can have components that function with only the data they need. or V.part = f(M.parts). basically a view-model from the model
header(...) and todoItem(...) would be concerned with different parts of the model
Fred Daoud
@foxdonut
Jun 28 2016 15:30
nothing stopping you from calling header(model.part) ;)
devin ivy
@devinivy
Jun 28 2016 15:31
@foxdonut i look forward to trying meiosis :)
Fred Daoud
@foxdonut
Jun 28 2016 15:32
I'm also using state and view-models.. but those can be implemented simply with functions, no need to burden the library with things when functions suffice
@devinivy thank you! :)
I will do some refactoring based on today's discussion -- a big thank you to everyone, this was interesting and helped clarify the... semantics!
Like I said, I didn't really like using update... I prefer what we discussed, i.e.
Riccardo
@riccardoferretti
Jun 28 2016 15:35
looking forward to it @foxdonut !
Fred Daoud
@foxdonut
Jun 28 2016 15:37
  • initialModel: {...}
  • actions: function(propose)
  • view: function(model, actions)
  • receive: function(model, proposal)
  • nextAction: function(model, proposal, actions)
  • postRender: function(view)
  • ready: function(actions)
where postRender is anything you need to do after each render (don't need it most of the time, but in some edge cases like focus with plain HTML)
and ready is for any one-time initial code you need at startup
everything is optional, so you use what makes sense in e.g. a root "master" component vs a small view component
happy to hear it @riccardoferretti thank you!
Edward Mulraney
@edmulraney
Jun 28 2016 15:46
is nextAction (nap), simply another action from the available acitons?
that is always executed after what?
Michael Terry
@formido
Jun 28 2016 15:52
I like send and receive
that's what I named them a couple days ago in a SAM inspired phantomjs script I wrote
Fred Daoud
@foxdonut
Jun 28 2016 15:52
@edmulraney : nextAction(model, proposal, actions) always gets called, but in your function you determine whether or not to call actions.somethingElse() to automatically trigger another action. You use model and/or proposal to decide. Of course, you could use a state object and wrap the function call with it and call something like if (state.something(model) { actions.something(); }
Michael Terry
@formido
Jun 28 2016 15:52
that's the language used for message passing in erlang
Fred Daoud
@foxdonut
Jun 28 2016 15:54
const nextAction = state => (model, proposal, actions) => {
  if (state.counting(model)) {
    if (model.counter > 0) {
      actions.decrement(model.counter);
    }
    else if (model.counter === 0) {
      actions.launch();
    }
  }
};
Edward Mulraney
@edmulraney
Jun 28 2016 15:54
so, does this get called straight after render?
Fred Daoud
@foxdonut
Jun 28 2016 15:57
render -> postRender -> nextAction
Edward Mulraney
@edmulraney
Jun 28 2016 15:57
is postRender in JJ's SAM description, or something in Meiosis?
Fred Daoud
@foxdonut
Jun 28 2016 16:01
it's something in Meiosis. like I said, rarely needed.
Edward Mulraney
@edmulraney
Jun 28 2016 16:01
thanks @foxdonut :)
Fred Daoud
@foxdonut
Jun 28 2016 16:01
welcome @edmulraney !
Edward Mulraney
@edmulraney
Jun 28 2016 16:02
This message was deleted
it's permissable to fire multiple actions.blah() within a nextAction?
const nextAction = state => (model, proposal, actions) => {
  if (state.counting(model)) {
    actions.decrement(model.counter)
    actions.systemAlert(model.blah)
    ...
Fred Daoud
@foxdonut
Jun 28 2016 16:09
if it makes sense in your application
@edmulraney you could also have a sequence of actions (one after the other) but in that case your nextAction function would use state to determine which one to fire.
Edward Mulraney
@edmulraney
Jun 28 2016 16:12
how would you handle a situation where in your sequence of actions, the first action results in an asynchronous call, and the second action depends on the result of the first?
const nextAction = state => (model, proposal, actions) => {
  if (state.counting(model)) {
    actions.decrementAsync(model.counter)
    // need to wait for the above action to complete, then the next action is fired with the new model data
    actions.systemAlert(model.blah)
    ...
Fred Daoud
@foxdonut
Jun 28 2016 16:16
  • make asynchronous call
  • in the function that receives the result, call propose(proposal) according to the result
  • in receive, update the model as appropriate, given the proposal
  • in nextUpdate, call the next action based on the model and/or the proposal
Edward Mulraney
@edmulraney
Jun 28 2016 16:19
unit-of-work would make the asynchronous call, but in our nextAction we don't know when that's completed, and we can't .then() on actions
so it seems like we can only put multiple actions.blah() in nextAction if they result in a synchronous unit-of-work
any thoughts on this anyone?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:29
@edmulraney you can never trigger multiple actions
the semantics is that an action is part of a step, a new action can be triggered at the end of the step
Edward Mulraney
@edmulraney
Jun 28 2016 16:30
how do you trigger a new action automatically, at the end of a step?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:30
you cannot trigger an action without knowing the application state
if (condition) { actions.doThis() }
Edward Mulraney
@edmulraney
Jun 28 2016 16:30
if its synchronous then you know the application state, so you could do multiple
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:30
you can queue actions but you should try to avoid executing an action without knowing that it is allowed
Edward Mulraney
@edmulraney
Jun 28 2016 16:31
@jdubray that example is how to invoke an action, you've said you can't place that in NAP, so where does it go
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:31
that's what you put in nap()
Edward Mulraney
@edmulraney
Jun 28 2016 16:31
im talking about the 2nd action you want to do
not the first
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:31
nap is at the end of the step, to it's in the best position to know what to do
in nap() you'll have something:
if (condition1) { actions.action1(..) ; }
if (condition2) { actions.action2(..) ; }
condition2 will have to be designed to know that action1 has completed
You can also do a functional composition of actions
but logically you only execute one action (one step, one allowed action)
Edward Mulraney
@edmulraney
Jun 28 2016 16:33
what if you need to do two actions in one condition? if(condition1) { actions.action1() actions.action2()}
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:33
by definition you cannot
one action = one step
that's the semantics
Edward Mulraney
@edmulraney
Jun 28 2016 16:33
then how do I achieve this goal in SAM
of executing two or more actions
its a common use case:
  1. Action1: fetch something from API
  2. Action2: depending on result of API - do something..
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:35
as I said two ways:
  1. functional composition composite_action = action2(action1(data)) (action1 presents its data to action2 which presents it to the model)
  2. step/nap based , in nap:
    if (action1Completed) { actions.action2({ } ) ;}
Edward Mulraney
@edmulraney
Jun 28 2016 16:35
oh i see. I forgot nap would cause the loop to start again and retrigger nap
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:35
you cannot dissociate actions to a "Step", that's why an action is not just a function call
the nice thing about nap is that you achieve what Sagas do (some logic if action1 failed, ...) but in a stateless way
Edward Mulraney
@edmulraney
Jun 28 2016 16:36
if(action1WasSuccessful) where would you suggest storing this temporary state?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:36
the application state remains 100% in the model
in the model
Edward Mulraney
@edmulraney
Jun 28 2016 16:37
does that not dirty the model a bit?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:37
single state tree is something you never want to break
well, you can decompose the model into modular parts
Edward Mulraney
@edmulraney
Jun 28 2016 16:37
sure, but i mean storing temporary state
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:37
you can also create parent/child SAM instances
Edward Mulraney
@edmulraney
Jun 28 2016 16:37
state would become filled with temporary data
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:38
the alternative is something like Sagas, not really pretty
State is ugly in general, you can only make it less ugly
Edward Mulraney
@edmulraney
Jun 28 2016 16:39
model.feature.component.action-wasSuccessful
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:39
yes
Edward Mulraney
@edmulraney
Jun 28 2016 16:40
model.feature.component.action-responseData
the unit-of-work may not perform a model-mutation based on it's response, but we still want the response data. s i suppose it would go in the above temporary model property
okay that makes sense now. thanks @jdubray. I'm impressed with how few libraries you'd need to do this. say compared to redux
it just needs a strong blueprint/skeleton/folder-file organisation, and minimal wiring
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:43
yes, that's why I often say I can replace React+Redux+Sagas+Thunks+... with one line of code
I am exaggerating a bit of course, but you can see it too
Edward Mulraney
@edmulraney
Jun 28 2016 16:43
well we've always been able to do that, but redux was trying to organise project sensibly, this seems like a more sensible organisation, without the need of so many tools
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:44
yes exactly the assembly is very flexible because I believe it's based on an efficient factoring
yes !
the proposal/acceptance is very powerful
and then things like nap come handy when you need them
Edward Mulraney
@edmulraney
Jun 28 2016 16:44
I'm nearly ready to admit that I'm sold ;)
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:45
!!!!!! thank you!!
to be fair, you are really sold on TLA+, SAM is just one way this incredible piece of work can be helpful!
Edward Mulraney
@edmulraney
Jun 28 2016 16:45
sensible semantics/assembly means we wouldn't need a redux style eco-system. just write plain JS. big wins
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:45
YES!! YES!!
I have nothing against frameworks and libraries, but you have to know why you use them
Edward Mulraney
@edmulraney
Jun 28 2016 16:46
redux (done right), without redux
Jean-Jacques Dubray
@jdubray
Jun 28 2016 16:47
yes, again nothing against React/Redux, very innovative, very inspiring, but they need to clean it up
they cannot let it grow in such a chaotic way
SAM also show that your programming model should be agnostic to the way you wire your application and cross tiers (Isomorphic Javascript)
If wiring is central to your code and you pain writing Isomorphic JS, you are doing something wrong
IMHO
This is the same lesson for old Java (EJB for instance).
Your code cannot be tier specific or protocol specific, period.
Edward Mulraney
@edmulraney
Jun 28 2016 16:52
in a lot of examples, actions are global to window. is model preferred location for these?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:12
they are just sample code to reason about, it's really your choice how you want to mount/wire the pattern
it's just a pattern!
Edward Mulraney
@edmulraney
Jun 28 2016 17:15
yep, as long as there are no issues with putting it in model, i'll do that
what term are you using to describe components/features/modules/"ducks" in SAM?
i.e. collection of intents/actions/view-components/control-states, for a single "component"
Fred Daoud
@foxdonut
Jun 28 2016 17:21
Agree @edmulraney @jdubray why I am sold also is that it's just simple JS
Meiosis is not a framework, just a small helper library to do the wiring. The initial code was very small. Now, it's not that it's much bigger, just that it's written in TypeScript (for those who like those benefits) and broken up better. It's still very simple. You might have the reaction "I could have written this myself" and to that I'd say "great! that's the idea! it's simple. no black-box esoteric angular magic here."
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:26
but it solves a very real problem which is being able to substitute the view if you need to. That's the kind of problems you want some help with.
@edmulraney I am not very good with naming things :-)
Edward Mulraney
@edmulraney
Jun 28 2016 17:27
i think it's not obvious that the redux-thunk+redux-blah approach is bloat until you see you can implement a redux style loop with clearer semantics and less boilerplate
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:28
thank you!
Edward Mulraney
@edmulraney
Jun 28 2016 17:28
although i did have to write something similar to what @foxdonut has written (mini framwork/blueprint)to gain this understanding
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:29
The big lesson I learned with SAM/TLA+ is that when your semantics are not aligned with what you are doing you quickly get lost in boilerplate
And we have not even started to discuss what the Paxos part can help do for you in an IoT/Wearables/Multi-User world
http://harry.me/blog/2014/12/27/neat-algorithms-paxos/
When you understand how you can weave paxos into our architecture, the sky is the limit.
But first you need to understand SAM, if I introduce Paxos, lots of people will run away
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:34
SEQUENCE NUMBERS
[The proposal] holds inside it the value being proposed, as well as what’s called a sequence number inside it. The sequence number is generated by the proposing process, and it declares that the receiving process should prepare to accept a proposal with that sequence number. This sequence number is key: it allows processes to differentiate between newer and older proposals. If two processes are trying to get a value set, Paxos says that value proposed last should take precedence, so this lets processes figure out which one is last, and thus who is trying to set the most recent value.
Edward Mulraney
@edmulraney
Jun 28 2016 17:35
nice blog post
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:35
Dr. Lamport spent 20-30 years to get these semantics right, they deserve our attention
Edward Mulraney
@edmulraney
Jun 28 2016 17:36
had Dr. Lamport thought about applying these principles to the UI?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:36
no, he is focused a different kind of problems.
Edward Mulraney
@edmulraney
Jun 28 2016 17:37
did he think it was a good idea when you spoke to him?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 17:37
He is very busy, so he delegated the review to someone else
they concluded it was not worth their time, but interesting enough to look at it
I respect that, I was already infinitely grateful to have a conversation to understand how TLA+ works
For instance, Dr. Lamport has spent a lot of work connecting Mathematics and Computing, I guess that's a lot more interesting than Front-End/Redux stuff
He is still working on the semantics of TLA+, that's also more important than finding more use for it
He should be looked at as the Alan Turing of our time.
Jean-Jacques Dubray
@jdubray
Jun 28 2016 19:26
Here is another article on the Paxos protocol: https://angus.nyc/2012/paxos-by-example/
Fred Daoud
@foxdonut
Jun 28 2016 19:38
@jdubray interesting, does SAFE implement Paxos?
Jean-Jacques Dubray
@jdubray
Jun 28 2016 19:46
A small variant, because it keeps track of the action instance id, when an action is triggered, it gets a unique step/action id which will come as part of the proposal, the SAFE middleware will filter "out-of-step" proposals without the Model knowing about it.
SAFE makes all this transparent to the action and model (the step/action id is injected at the dispatcher level)
Feel free to reuse the code (with credit), I am ok with it.
This is a great value add
SAFE is here to illustrate the power of the factoring, as I said, I think the sky is the limit. Imagine the kind of multi-user/concurrent experience you can create with that.