These are chat archives for jdubray/sam

25th
Feb 2016
Michael Terry
@formido
Feb 25 2016 16:51
Top comment on this current Hacker News thread about core.async and CSP brings up TLA+: https://news.ycombinator.com/item?id=11174806
Lee Owen
@fleeboy
Feb 25 2016 16:53
@formido Thats a great video he posted -I watched it yesterday. Lamport explains whats wrong with not creating a spec before coding
Michael Terry
@formido
Feb 25 2016 17:01
I'll have to watch it
Jean-Jacques Dubray
@jdubray
Feb 25 2016 17:21
@fleeboy how about coding with the right blueprint?
thank you for sharing @formido great video!
edbienes
@edbienes
Feb 25 2016 17:24
@formido thanks for the link! Watvjing
... Watching the video now :+1:
Jean-Jacques Dubray
@jdubray
Feb 25 2016 17:47
Just want to add that in general you can write code (say algorithms) with a TLA+ structure, it would not be the best performing code. It works well at the Front-End architecture level because, it adds very little overhead compared to processing "units of work" represented by actions. Actions are triggered by "big" events like submit a form for instance, actions are not just another function call. However a TLA+ based structure will give you much more robustness than without it.
The typical errors a developer would make would include:
  • calling multiple actions (which eventually mutate the state) without checking if the system is in a state where it is even possible (no State function)
  • coupling the code that computes proposed values to mutate the model with the code that mutates the model (no present function)
  • includes control state checking within the action code (no nap function)
    ...
    ultimately these poor choices will lead to buggy, hard to reuse and hard to maintain code
Phips Peter
@pspeter3
Feb 25 2016 17:54
Hi, I'm just going to listen and learn for a while.
Jean-Jacques Dubray
@jdubray
Feb 25 2016 17:54
welcome to the list
Phips Peter
@pspeter3
Feb 25 2016 17:56
Thanks!
Michael Terry
@formido
Feb 25 2016 19:03
@jdubray In Rocket Launcher, representation() is vm() right?
Lee Owen
@fleeboy
Feb 25 2016 19:11
@formido I wasn't sure if it was as all it's doing is selecting the correct view based on the model. If it did more work like filtering the model to a smaller view model just to pass to the view rather than the whole model?
not sure if it's the right place to do that or create a new wrapping function that takes the model and current state and produces a filtered view model?
Michael Terry
@formido
Feb 25 2016 19:18
Well, I want to make a clear mental map between V = S( vm( M.present( A(data) ) ), nap(M)) and Rocket Launcher
In here:
state.render = function(model) {
    state.representation(model)
    state.nextAction(model) ;
}
nextAction() is clearly labelled as a peer of representation()
So, I'd assume that picking which view code to display based on the control state would be part of the vm() purpose
that's my reasoning
Michael Terry
@formido
Feb 25 2016 19:31
I would think filtering the model would also go in representation(), if necessary, where it would use the filtered model to switch on the states to choose the view code
Michael Terry
@formido
Feb 25 2016 19:50
So what I see is an action A() is initiated, which calls model.present() (M.present()), which calls state.render (S()) which calls state.representation (vm()), which calls state.nextAction() (nap()), which either starts the reactive loop again or the system waits for an external action to trigger another loop
Lee Owen
@fleeboy
Feb 25 2016 19:53
Well, when you explain it like that, it makes perfect sense to me 👍
Jean-Jacques Dubray
@jdubray
Feb 25 2016 19:53

@formido

in Rocket Launcher, representation() is vm() right?

no representation is the state representation (aka the View). vm() is optional it is the View-Model function which adapts the model to the view (conversation, parameter mapping, ...)

Michael Terry
@formido
Feb 25 2016 19:54
where is view in V = S( vm( M.present( A(data) ) ), nap(M))
?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 19:54
If there was a View-Model function it would have looked like that:
state.render = function(model,vm) {
    state.representation(vm(model))
    state.nextAction(model) ;
}
Michael Terry
@formido
Feb 25 2016 19:55
oh, I see
heh
got it
Jean-Jacques Dubray
@jdubray
Feb 25 2016 19:55
In general you don't want to pass the whole model to your components
Michael Terry
@formido
Feb 25 2016 19:56
@fleeboy was right then
Jean-Jacques Dubray
@jdubray
Feb 25 2016 19:56
For instance a countDownComponent would only take counter as an argument
Lee Owen
@fleeboy
Feb 25 2016 19:56
Lucky guess lol
Jean-Jacques Dubray
@jdubray
Feb 25 2016 19:56
yes, he was
You need vm when you have also some logic that would repeat in different components (unit conversations, derived values, ...)
You want the component to be as dumb as possible
Lee Owen
@fleeboy
Feb 25 2016 19:58
that clears that up nicely
Michael Terry
@formido
Feb 25 2016 19:59
Ok, so vm() would divide up the model and dispatch pieces of it to the appropriate component functions to get their view code?
This message was deleted
This message was deleted
Lee Owen
@fleeboy
Feb 25 2016 20:04
Vm() will filter the model and the result will be passed to representation()
so the state predicate will need to be tailored to the view model as that is what it switches on the select the correct view?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:20
The (new) state function, has access to the entire model, and therefore can calculate what is the current (control) state and decide which component to render. Again, you don't have to calculate the control states the way I do it in the rocket example, it can be achieved with simple if-then-else if (launched) { views.launched(model.counter,...) }
The idea of the pattern is really to have enough structure to position each type of code in the right bucket (V, S, nap, M, A)
It's really up to you how you code each bucket. With the rocket example I wanted to show that one of the big advantages of the pattern is that it aligns naturally with State Machines. That means if you ever need them, then it works.
My recommendation is always to put the code you write in the right bucket
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:25
For instance we can see in Redux thunk examples that they define a new action inside which there is a test that when false, actually does not dispatch the function. That is the kind of thing that SAM helps you avoid. In SAM the test wether an action will be dispatched will be in nap with full access to the model, but the action itself, will be like a view a simple function with some inputs (obviously some values from the model), and some outputs. In SAM there is never a need for an action to know the entirety of the model, that makes the action highly reusable across solutions
In some cases nap will evaluate the state to be the one which has no automatic action, for an other state it will dispatch the automatic action.
Michael Terry
@formido
Feb 25 2016 20:28
What if a page has multiple components?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:28
It does not sound like much, but this is the kind of factoring that makes your code a lot more maintainable, with less bugs
Michael Terry
@formido
Feb 25 2016 20:28
One loop handles them all, right?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:28
That's easy, yes, just like in React, you have a "tree" of components
Lee Owen
@fleeboy
Feb 25 2016 20:28
@formido I am thinking hierarchical state machine for that
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:29
No, for the view/state representation, you are outside the state machine
you are simply computing the state representation
function f(model) { 

      views.body(model, 
                  views.component1(model.x, modely) 
                + views.component2(model.u)
                + ...
}
Lee Owen
@fleeboy
Feb 25 2016 20:32
are those components the pure function of the model?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:32
The problem with react is that it has its own hierarchical composition mechanism, it's much much easier to compose with function
yes, no state at all (other than say config state)
Lee Owen
@fleeboy
Feb 25 2016 20:33
so those, in redux speak, are "dumb" components
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:33
Of course the view contains data elements of the model, but not as in state, it is rather the "display" which contains these data elements
Yes, absolutely
Lee Owen
@fleeboy
Feb 25 2016 20:34
what about components that are stateful and have their own inner state
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:34
Very similar to React, but just pure javascript function. I believe the React team went overboard when they design React
Lee Owen
@fleeboy
Feb 25 2016 20:34
amd you have several on a single "page"
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:34
You can use closures
But again, the inner state is pure config, no model dependencies
Lee Owen
@fleeboy
Feb 25 2016 20:35
so you could be passing a huge model around potentially?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:36
Yes, you can have as many components as you want. It forces the front end developer to think in terms of "given the values of the model, what my view looks like", but then immediately decomposing it into components
You no longer need to think in terms of "pages", more like "activities"
For true single page applications this is gold because the user never feels you are changing pages
@fleeboy yes, there is not much option there, after that "caching" or "diffing" would have to come into play.
There is no magic in SAM. If you are building Facebook, perhaps you need more than SAM, but for 98% of Web apps, I'd argue you don't need more than SAM.
Lee Owen
@fleeboy
Feb 25 2016 20:40
ok. So if you had a complex control panel for example, and several of the components needed to track their own state would they use a state machine with "lots" of states or a large switch statement?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:41
An example where you may need "state" in a component is a graph view, with lots of data, you would add one point at time, but you cannot afford to redraw the entire component each time
You can compose the pattern as in fig6 of the paper, so if you can you should have components to remain as dumb as possible, but as mentioned in the graph example, it's not 100% always possible.
Michael Terry
@formido
Feb 25 2016 20:44
which paper?
Michael Terry
@formido
Feb 25 2016 20:46
I see
I thought you were pointing to a different composition of SAM to handle the "stateful graph component"
Lee Owen
@fleeboy
Feb 25 2016 20:47
ok that's fair enough. Would the pattern work for a stateful component (it has its own model and state machine) nested within a Master component with multiple peer stateful components? The stateful components model would be a sub model of the Master component. Would that work?
Jean-Jacques Dubray
@jdubray
Feb 25 2016 20:49
SAM works at any level... but when you start having too many instances of SAM running in the hierarchy, you easily get lost. Fig6 suggests a common view for both instance, which is a very interesting composition mechanism if you ask me.
Lee Owen
@fleeboy
Feb 25 2016 20:51
I would disagree there. Self contained components with their own SAM instance would be easier to reason about in my opinion
Michael Terry
@formido
Feb 25 2016 20:52
isn't figure 6 just the normal SAM pattern?
Lee Owen
@fleeboy
Feb 25 2016 20:52
they could be dropped into any Master Sam instance and as long as they get their model requirements fulfilled they would work
Michael Terry
@formido
Feb 25 2016 20:54
sort of like the client/server composition model?
client components as self-contained SAMs
Lee Owen
@fleeboy
Feb 25 2016 20:56
Yes that's it
handling the nesting should be straight forward as the Master component would filter the master model for each sub component
Michael Terry
@formido
Feb 25 2016 21:00
I can see that being a good idea in some cases
Lee Owen
@fleeboy
Feb 25 2016 21:01
complex cases most likely! Probably overkill and getting too close to React!
Jean-Jacques Dubray
@jdubray
Feb 25 2016 21:02
yes, sorry, I meant fig 9
I have to work now, sorry, have to check out
The display is responsible for mounting the state representation
Michael Terry
@formido
Feb 25 2016 21:03
Np, this convo has helped my understanding a ton
Jean-Jacques Dubray
@jdubray
Feb 25 2016 21:03
any time
Lee Owen
@fleeboy
Feb 25 2016 21:03
ok thanks jj
Jean-Jacques Dubray
@jdubray
Feb 25 2016 21:03
At the end of the day you have React+Redux+Saga+Thunk in one line of code: V = S( ...)
that's the value SAM brings. Not claiming it covers 100% of all cases or you'll never need react
but react makes a lot of things really hard for no particular reasons
ok, have to go
Michael Terry
@formido
Feb 25 2016 21:04
later
Brian Haak
@avesus
Feb 25 2016 21:16
Which difference between State and Model?
Michael Terry
@formido
Feb 25 2016 21:19
The model is the set of properties and validation rules for the app
The state is an object that gets the current representation of the app and calls nap() on it
V = S( vm( M.present( A(data) ) ), nap(M))
gets the current view representation of the app
Michael Terry
@formido
Feb 25 2016 21:24
In SAM, State doesn't hold any state, it's just a function
Brian Haak
@avesus
Feb 25 2016 21:27
I'm trying to figure out the architecture in pure functions. Please, clarify what are these data and how to got the idea without objects, just in pure functions receiving and returning data. Looks too weird for me without complete understanding of modeling Paxos in TLA+.
Sure, it will popularize the idea and forces Dan to popularize it too. The industry needs that understanding!
Michael Terry
@formido
Feb 25 2016 21:29
I think you'll have to wait for @jdubray to reappear...he just left
I don't want to say anything that's not 100% right as I'm just getting a feel for it myself
I would start by looking at Rocket Launcher closely: https://bitbucket.org/snippets/jdubray/9dgKp/sam-sample
And then reading back on this channel a few pages
Michael Terry
@formido
Feb 25 2016 21:36
I will note:

Wiring
The SAM pattern can be described as a Mathematical expression (formula):

V = S( vm(M.present(A(data))), nap(Model) )
Where S(), vm(), A() and nap() are pure functions with respect to the model.
However, that expression is only a logical expression that describes the sequence in which the elements of the pattern are invoked. The expression itself is not representative of the Reactive Flow or the different wiring options.

Brian Haak
@avesus
Feb 25 2016 22:33
Thanks a lot. But I don't see how an app in SAM approach could be scaled and componentized vertically (I totally agree with the idea of buckets).
Jean-Jacques Dubray
@jdubray
Feb 25 2016 22:46
@avesus the model is what is called the application state (property and values)
The state is the "control" state (e.g. a car is in the control state started or stopped)
Control state is a function of the model started = rpm > 0 ;
Jean-Jacques Dubray
@jdubray
Feb 25 2016 23:16
SAM works the same way any components hierarchy scale. Let me illustrate with one example

If you to to http://www.michelduran.com
you'll see that parts of the site are built from the same component (bio and films, then for each films, and so on)
How was that build following the V = f(M) model?
So first how we put mount all the components inside f():

                +   theme.sliders(home.sliders) 
                +   theme.actors(home.bio)
                +   theme.clearFix() 
                +   theme.actors(home.films)
                +   theme.clearFix()  
                +   theme.trailer(home.trailer)
                +   theme.clearFix() 
                +   theme.trailerInfo(home.trailerInfo)
                +   theme.clearFix() 
                +   theme.trailer(home.trailerReel)
                +   theme.clearFix() 
                +   theme.trailerInfo(home.trailerInfoReel)
                +   theme.clearFix() 
                +   theme.trailer(home.trailerCalBalloons)
                +   theme.clearFix() 
                +   theme.trailerInfo(home.trailerInfoCalBalloons)
                +   theme.clearFix() 
                +   theme.trailer(home.trailerTheatre)
                +   theme.clearFix() 
                +   theme.trailerInfo(home.trailerInfoTheatre)
                +   theme.clearFix() 
                +   theme.trailer(home.trailerOmbre)
                +   theme.clearFix() 
                +   theme.trailerInfo(home.trailerInfoOmbre)
                +   theme.clearFix() 
                +   theme.trailer(home.trailerOntherun)
                +   theme.clearFix() 
                +   theme.trailerInfo(home.trailerInfoOntherun)
                +   theme.clearFix() 
                +   theme.callToAction(home.callToAction)
                +   theme.clearFix() 
                +   theme.gallery(home.gallery) 
                +   theme.clearFix() 
                +   theme.contact(home.contact)
                +   theme.clearFix()

each component of course being a pure function

then focusing on the actor component:

theme.actors = function(a) {
    a = a || {} ;
    a.id = a.id || 'actors' ;
    a.title = a.title || 'TITLE' ;
    a.title2 = a.title2 || 'TITLE2' ;
    a.title3 = a.title3 || 'TITLE3' ;
    a.title1 = a.title1 || 'TITLE1' ;
    a.p1 = a.p1 || 'SUMMARY1' ;
    a.p2 = a.p2 || ' ' ;
    a.p3 = a.p3 || ' ' ;
    a.background = a.background || 'html/img/background/5.jpg' ;
    a.actors = a.actors || [{}] ;
    if (a.actors.length>3) {
        a.background = 'html/img/background/5b.jpg' ;
    }
    var actors = '' ;
    if (a.actors.length>0) {
        actors = a.actors.map(function(actor){
            actor = actor || {} ;
            actor.name = actor.name || 'NAME' ;
            actor.surname = actor.surname || 'SURNAME' ;
            actor.img1 = actor.img1 || 'html/img/actor/3.jpg' ;
            actor.img2 = actor.img2 || 'html/img/actor/hover/3.jpg' ;
            var img2 = '' ;
            if (actor.img2 !== undefined) {
                img2 = '<img class="before" src="'+actor.img2+'" alt="actor">\n' ;
            }
... 
return ('<!-- ACTORS -->\n\
            <section id="'+a.id+'">\n\
                <div class="center">\n\
                    <!-- title -->\n\
                    <h2 class="title">'+theme.localize(a.title)+'</h2>\n\
                    <!-- actors -->\n\

Now last part is the model:

home.bio = {} ;
home.bio.id = 'bio' ;
home.bio.title = 'Biography' ;
home.bio.title1 = 'Michel Duran is a Franco-Canadian actor, director and producer' ;

you see the id? each component will have a different id, just like any button, link, ...
Happy to share more privately
now the main menu has the same references:

home.menuItems = [{link: "#films", label: "FILMS"}
                ,{link: "#theatre", label: "THEATRE"}
                ,{link: '#gallery', label: "GALLERY"}