These are chat archives for jdubray/sam

8th
Jun 2016
Fred Daoud
@foxdonut
Jun 08 2016 01:11
@jdubray thanks again for your feedback. Your point about state is well taken by me. I explored incorporating it into Meiosis. Then I realized that there is no need to change the wiring, since state is a smart object that determines the state based on the model; it determines the display based on the current state and using the views; and it determines the next action. So, the display is ultimately a function of the state; receiveUpdate (or model.present) is also a function of state; and finally next is a function of state. Using higher-order functions to wire this together makes it very clean: http://codepen.io/foxdonut/pen/rLVRPR?editors=1010
As a bonus, there is no need for a separate viewModel, since state, as you have said previously, can also prepare data for the view. This simplifies Meiosis! I like this approach. Merci beaucoup JJ I will update the documentation to reflect the importance of the state object.
Jean-Jacques Dubray
@jdubray
Jun 08 2016 01:21

Great! I am glad I convinced you. I feel that SAM can relatively easily fit in a lot of existing approaches. In the end, it's only a factoring of the business logic in three distinct buckets (propose/accept/learn). You can do that any way you want. I can see every a lot of sample code where this is not the case, and I feel they are missing on a lot of value.

Then the second (or first) principle where V = f(M) is a bit harder to factor in, clearly Angular2 has not learned any lesson from React. IMHO, templates must go. I am glad there are now a lot of alternatives (to React) to build this: Snabbdom, Inferno, ... vanilla.js.

I think it would be very helpful to provide a V = f(M) framework for Angular2.

@foxdonut

So, the display is ultimately a function of the state; receiveUpdate (or model.present)

yes, I agree, since only the model invokes the State function, you can easily factor it in. It would certainly make me happy if recommend the full factoring Propose/Accept/Learn, rather than making the State optional.

Merci!

Jean-Jacques Dubray
@jdubray
Jun 08 2016 02:12
This message was deleted

@edmulraney @dagatsoin SAM is very simple.

SAM suggests that the business logic should be factored along three concepts: actions, model and state. Actions propose values to the model, which is solely in charge of accepting them, once accepted, the state makes sure that everyone who needs to learn about these new values is notified, in particular the view which is considered as the “state representation”. Every event is processed as a “step” which involves a propose/accept/learn flow. This concept provides a stronger foundation to deal with event ordering and effects (such as back-end API calls).

SAM is framework agnostic and several people in this room went on to build a series samples with different frameworks.

The problem that we are all trying to solve is how to go from an event to a proper state representation (view) displayed to the user(s). There are of course different ways to do that. For instance mobX has initially focused on "hard-wiring" event to view (in a spreadsheet way).

SAM is simply saying that whatever happens between the event and the view is best represented by a "step" including propose(actions)/actions(model)/learn(state).

Jean-Jacques Dubray
@jdubray
Jun 08 2016 02:21
I am not sure spreadsheets work differently, really all I am suggesting is for people to take a hard look at that factoring and objectively talk about what works and what doesn't. In particular is there any value in using "pure" functions (like Redux, Elm) or streams like Cycle.js.
Please note that Cycle, Elm and now MobX all found major issues with their original formalism:
Daniel Neveux
@dagatsoin
Jun 08 2016 08:29
@jdubray about SAM. It IS simple, yes, I honestly never seen a concept such minimalist and powerful, mostly in its decoupling potential.
But the way you explain it is not in the "main stream" way other library approache their community. I don't think the public who stick to react, angular, whatever, is ready for a such academic explanation (eg. just the formule, I spend days to understand a such simple thing) or high level computing science terms. I think it is the biggest issue in SAM. Honestly, it could be worth :)
It is my own opinion.
Jean-Jacques Dubray
@jdubray
Jun 08 2016 09:38
Ok, I hear you. I'll add an introduction over the next few days.
Jean-Jacques Dubray
@jdubray
Jun 08 2016 10:25

@dagatsoin thank you for sharing these references, please note the subtle variation in semantics:

“[Actions] Just do something to the state and MobX will make sure your app respects the changes.”

There is no phase "accept" in MobX, it is implied that the output of an action will be accepted (directly update the observable) and from there the UI will be rendered

On the positive side, MobX does not see any issue to invoke APIs within an action, that's good. That's one less point to disagree about.

@action    createRandomContact() {
        this.pendingRequestCount++;
        superagent.get('https://randomuser.me/api/').end(
            action("createRandomContact-callback", (error, results) => {
                const contact = new Contact(results[0])
                this.contacts.push(contact);
                this.pendingRequestCount--;
            })
        );
    }
Jean-Jacques Dubray
@jdubray
Jun 08 2016 10:30

Just to sum up, MobX was initially focused on the tail end of SAM well after the data was proposed and accepted and even after the State function decides what needs to be rendered.

Now, unfortunately, they have decided to add actions, but without a model or (control) state, let alone nap()

It's actually fascinating to study all these semantics (Redux, MobX, Cycle.js, Elm,...) and realize that each time they are missing some (imperceptible) element. Most people would argue what's the big deal about delineating propose vs accept or accept vs learn. And yet it changes completely the factoring of your code. On large projects this makes such a big difference.

Daniel Neveux
@dagatsoin
Jun 08 2016 10:43
yep, agree for the "accept" phase, but I am implementing right now and just replacing the direct mutation with a "present" function which does the job. The big addition for me is to be able to stick with SAM and mobx and to be able to enjoy the mobx-react-dev tools. (a sort of history of for my sam loop)
And yes, the other good point is too be able to do api call. The last thing I wonder if it integrates a way to allow only one action to mutate the model even if multiple actions are triggered.
Jean-Jacques Dubray
@jdubray
Jun 08 2016 11:08
@dagatsoin be careful, logically you cannot trigger multiple actions. Once an action is dispatched it has to go through the propose/accept/learn phase. What SAM supports is:
a) the concept of action "hang back" for long running actions. You can trigger multiple actions, the first one to present "wins" and all the others get rejected (this helps implement cancellations on long running actions)
b) a functional composition where the action is logically composed of several functions A(data) = f1(f2(f3(data))) which lead to a single proposal
I have reached out to the Mendix team to discuss these points
With actions, they should be in a much better position to be interested in SAM
Edward Mulraney
@edmulraney
Jun 08 2016 11:31
@jdubray Nice explanation. My impression is that you have a very clear mental model in your head of how SAM works, because you have a strong foundation in theory and TLA etc. - things that a lot of devs are unfamiliar with and probably acts as a barrier to SAM. I've been using redux in my contract for the past 8 months and was able to grok that much quicker than SAM. But as a comparison, the cyclejs website's approach to explaining how it works is very simple and combined with the presentations staltz made ("Dont React", etc.), its very easy to grasp quickly for non-academics and regular devs. Aurelia's approach was also successful in that they did direct code comparison's with other frameworks, which devs are familiar with, such as Angular, it demonstrated the benefit of Aurelia while also teaching how to use Aurelia, by mapping one mental model to another
It may not actually be that much of an issue, I just tried to show the architect of my previous contract the SAM pattern and his first comment was that the website was very heavy reading
Jean-Jacques Dubray
@jdubray
Jun 08 2016 11:35
Ok, I hear the feedback, will make corrections by end of the week
Edward Mulraney
@edmulraney
Jun 08 2016 13:34
It would be interesting to see if anyone else in here thinks the same thing? it's not worth fussing over if it's only myself and another dev that think this
Scott Conklin
@srconklin
Jun 08 2016 13:39

I am rather new to reactive/functional programming and had been going through the docs and the tutorials at Cylce.JS when I came across the SAM pattern. I read each of the topics at http://sam.js.org/ a few times. I decided I want to give it a quick test run and after studying the rocket example I converted a very simple app that I had learned over at Cycle.JS into the SAM pattern using plain JS.

The Cycle.JS version is here
http://jsbin.com/ritajuxele/1/edit?html,js,output
and what I came up with is here:
http://jsbin.com/sanepi/edit?html,js,output

You will notice that the slider (and the update) does not react very well at all.
Is this because that my view writes the entire DOM on every action triggered by the user? or is my implementation faulty?
I read somewhere that 95% of apps don't need a virtual dom.. is this a case where I do?

Jean-Jacques Dubray
@jdubray
Jun 08 2016 13:39
I think that's a constant feedback, so you are spot on.
@srconklin Let me take a look at it
devin ivy
@devinivy
Jun 08 2016 13:41
i agree that the site could communicate the core pattern more clearly for most folks. occasionally i think it tries to be concrete– for example by mentioning use of jquery– but at some cost of confusion. @jdubray if i find time and feel like i have a good way to reword anything on the site, i'll let you know. it's just really hard to communicate this stuff well.
@srconklin in this case you're continuously interacting with a slider. if a new slider appears it's going to forget that the user has clicked the slider knob and is dragging it.
Jean-Jacques Dubray
@jdubray
Jun 08 2016 13:44
@srconklin yes, that's the problem
Scott Conklin
@srconklin
Jun 08 2016 13:45
@jdubray That is what I guessed. So how best to approach the issue.. Introduce a vdom in the view like the cycle.js example? will that make it smooth?
Jean-Jacques Dubray
@jdubray
Jun 08 2016 13:45
The way out of it is to split the view in two elements you can independently render.
devin ivy
@devinivy
Jun 08 2016 13:46

I read somewhere that 95% of apps don't need a virtual dom

maybe true, but rerendering the whole UI does often lead to problems like this. there are ways to keep the DOM up to date other than virtual dom! for example, incremental-dom. the idea is to get more granular with what gets rerendered.

Jean-Jacques Dubray
@jdubray
Jun 08 2016 13:46
@devinivy how would the vdom solve that? would it not render the slider, while you are sliding it?
Scott Conklin
@srconklin
Jun 08 2016 13:46
@devinivy thanks. I will look at incremantal-dom
devin ivy
@devinivy
Jun 08 2016 13:47
@srconklin beware, it's very low-level :)
@jdubray yeah, vdom would not re-render the whole slider. i mean, it would probably re-render it virtually, but not in the DOM.
Scott Conklin
@srconklin
Jun 08 2016 13:48
@jdubray
"The way out of it is to split the view in two elements you can independently render."
Can you elaborate?
Jean-Jacques Dubray
@jdubray
Jun 08 2016 13:52
You'd need to differentiate between init and sliding states, the state function will then update each part of the view independently
state.representation = function(model)  {
  var representation =  { app: 'oops... something went wrong'}  ;
  if (model.sliding) {
        representation = { value: `Label: ${model.value} units`}
  } else {
        representation = { app: view.ready(model) } ;

   }
   view.display(representation);
};
The display method would look like that:
view.display = function(representation) {
  var thestate = document.getElementById("app");
  var thevalue = document.getElementById("value");
  if (representation.app) { thestate.innerHTML = representation.app; } 
  if (representation.value) {thevalue.innerHTML = representation.value;}
};
The initial state would be something like that:
view.ready = function(model) {
  return (
     `<div><span id='value'>Label: ${ model.value } units</span><input type='range' min='0' max='100' id='slider' value='${model.value }' onInput='JavaScript:actions.changeValue({value:document.getElementById(\"slider\").value})'></div>`
  );
};
Scott Conklin
@srconklin
Jun 08 2016 13:59
@jdubray Thanks! I will give this a try
Jean-Jacques Dubray
@jdubray
Jun 08 2016 14:01
sliding would be true when a value is presented to the model that is not equal to the model's value
Scott Conklin
@srconklin
Jun 08 2016 14:04

So the value attribute of the slider:

value='"  + model.value + "'

does not need to be reset on sliding?

Jean-Jacques Dubray
@jdubray
Jun 08 2016 14:27
I am expecting that it is holding its own value as it is sliding.
weepy
@weepy
Jun 08 2016 21:14
@edmulraney for what it's worth - I think you are absolutely spot on
@jdubray seems to have a pretty sweet idea in his head (SAM) - but as a coder I'd really like to see more concrete examples and less ethos (ie. it's cool that it's based on TLA+, but given that I know little about it, it doesn't help too much).
Edward Mulraney
@edmulraney
Jun 08 2016 21:15
sounds like it would be beneficial
weepy
@weepy
Jun 08 2016 21:17
Part of the issue is simply that SAM is a pattern, not a framework. Coders love frameworks since it gives boundries and structure to work with and learn. Patterns are of course more fundemental.
Edward Mulraney
@edmulraney
Jun 08 2016 21:19
very true
I'd like to help but I haven't had chance to really play with SAM yet. Hopefully this week