These are chat archives for jdubray/sam-examples

24th
Feb 2016
bgusach
@bgusach
Feb 24 2016 08:17

So no easy fix for my problem? :D

By the way @jdubray, what are your opinions about Ember? It offers some solutions to some of your problems. For instance, the models on the client don't have to match exactly what you are retrieving from the server. First you have a so-called "adapter" that can modify the data before it comes in or gets out, and then (and most importantly) your client models can have computed properties, e.g. if you have a Person model, and the age is coming from the server, you can define a property that computes on the fly "young" or "old" based on the age attribute.

Jean-Jacques Dubray
@jdubray
Feb 24 2016 09:25

sorry, I am not sure I fully understand your question.

what if I don't have a reference (even within a namespace) in the global scope? Thanks.

You'd have to dispatch the action in some ways, passing the corresponding parameters. Have you seen the example with Cycle.js?

Jean-Jacques Dubray
@jdubray
Feb 24 2016 09:31
Since the view is "generated" from the State which knows the allowed actions (and how to reach them) I don't see how you would not "have a reference".
bgusach
@bgusach
Feb 24 2016 09:50

@jdubray the problem I see is that, if I have a function myAction, and I want it to be bound to the onclick, I have to write (as a string) something like onclick="myAction". But that will only work if that function is reachable from the global scope, which is something you want to avoid at all costs when developing serious JS applications.

If I pack my whole application within an object that acts as a namespace, for instance MYAPP, and I expose my function there, I could write onclick="MYAPP.myAction", but still it would be better not to do so, and somehow bind the handler in another way.

Gunar C. Gessner
@gunar
Feb 24 2016 10:59
@jdubray I've put your Rocket example in a Fiddle. I've added a new button "Dummy Action" to test the nap() function. As I imagined, as your nap() doesn't know if it already has set a timer or not, it may set multiple timers i.e. running any other action during the countdown sets another timer. The end result is the same as these multiple timers don't interfere with one another, still, this could become a problem scaling. I don't like having to store a flag (mutate the state) just to indicate that a timer has been set. Do you know of any other solution?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:25
@bgusach when you consider that the view is "generated" (as in code generation), then there is no need whatsoever to bind handlers another way. You are thinking that someone writes the code, when in reality someone wrote the generator that wrote the code.
That's the absolute beauty of V = f(M)
sorry, I am an old MDSE guy (can't help it)
@gunar yes and no, because remember, unlike Redux / Sagas, SAM sequences precisely action-model-state. If you look at Redux thunks, they write a "script" regardless of the control state reached. That is fundamentally flawed. That is why I wanted to talk to Dan originally, because Redux is so close, but at the same time, it's leading people in the wrong direction. We are back to the usual action-oriented spaghetti.
Front-End Architecture is such a perfect use case for SAM, because precisely it is a state machine. That's why FEA failed for the past 40 years, because we all ignored the state machine beneath.
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:30
SAM works, because its semantics are precise enough. State machines don't work when you start writing (S1, A,B,C, S2)
Because After A, B may not be allowed, you can't arbitrarily write it that way
Gunar C. Gessner
@gunar
Feb 24 2016 11:34
Yes it's awesome not to have to worry about entering invalid states, but imagine a very complex app sending numerous actions, that'd trigger many timers. From a SAM perspective that's not a problem at all, but has performance costs on the browser. But I guess that's beyond the scope of this discussion.
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:36
Performance, IMHO is never a problem these days. Whenever there is a performance bottleneck we always found a way to fix it (virtual-Dom for instance).
Remember, you also don't have to follow the exact semantic of SAM if you know what you are doing. In other words, that's what we have been doing for decades, writing state machines as a series of actions. The problem is that we rarely know what we are doing and SAM provides just enough constrains to eliminate most problems without much overhead.
Algorithms tend to not require patterns like SAM, so I am not suggesting that we start using SAM everywhere all the time. I am saying however that SAM semantics (TLA+) work everywhere all the time, so when you see value over more "optimized code" you should go back to the basics of SAM.
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:42
That's what AWS is doing when they use TLA+. They write some code, but it's buggy, and the only way for them to find the bug is to "simulate" their code with TLA+. However for optimization reasons, they would not write it following the TLA+ semantics
Does that make sense?
Gunar C. Gessner
@gunar
Feb 24 2016 11:43
"Simulate"? They rewrote parts of their software in TLA+ patterns just to better understand the system?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:47
yes, this is what TLA+ is, it's not a programming language, it is a formal method to analyze code
Since I learned about TLA+, I have looked at ways to use the semantics as you code so you have less bug to analyze later...
I am lazy :-)
Gunar C. Gessner
@gunar
Feb 24 2016 11:49
Awesome
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:50
But again, that's not a way to write all your code.
I'll never make that claim
adonirammedeiros
@adonirammedeiros
Feb 24 2016 11:58
@jdubray how do you compose larger SAM components with small ones? There's some way to do this?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 12:04
It works at the view level, view can call actions at any level. comp
I can't claim you can nest n-level, but 2-3 levels should be ok.
Would that work for you?
adonirammedeiros
@adonirammedeiros
Feb 24 2016 12:13
The way you describe it seems that I will use the actions from low levels in high level views. I wondering about composing views too. For example, I have a SAM components handling different things with different views and I need to compose then on a larger SAM component that orchestrate then.
bgusach
@bgusach
Feb 24 2016 13:54
@jdubray, I think you did not understand what I said about attaching handlers to DOM Nodes built by string concatenation... anyway, it is just an implementation detail for HTML, nothing to spend too much time on.
Gunar C. Gessner
@gunar
Feb 24 2016 14:32
@bgusach you could try checking out how react does it. perhaps even Inpecting a React app through Developer Console could give you a hint. I'm curious too so let me know if you find something interesting.
@adonirammedeiros so you don't want your low level views/actions to know about higher order SAM cycles?
Hmm... perhaps the inner Model could be a part of the outer Model. Sharing parts of the Store.
Gunar C. Gessner
@gunar
Feb 24 2016 14:38
I (we?) haven't yet thought about SAM "components" , but rather as an architecture for whole apps.
Gunar C. Gessner
@gunar
Feb 24 2016 15:32
@bgusach I think that because React uses var el = createElement - instead of creating elements on the fly with strings - it can do e.g. el.onClick = ...
you could do that - and I've done it before - if you give the node an id (e.g. <button id="send">) and then attach all event handlers after view rendering (e.g. document.getElementById('send')). Remember to have unique IDs.
I don't see another solution atm. Either that or using global references.
bgusach
@bgusach
Feb 24 2016 16:01
@gunar, yes most of libraries create DOM Nodes via createElement, and then with the DOM Node you just have to set onClick or append an event listener. The idea of the IDs is not very practical in my opinion... somehow you have to keep track of the IDs and then attach the handlers. Looks like more work and not so clean information workflow (normally you would like to append the handlers when creating the code for the view). I have found the minimalistic library hyperscript quite nice, and the virtual-bom library is based upon this, which makes easier moving from raw re-rendering to a virtual dom approach.
Jean-Jacques Dubray
@jdubray
Feb 24 2016 16:08

@bgusach I was responding to this question:

The idea of the IDs is not very practical in my opinion... somehow you have to keep track of the IDs and then attach the handlers.

This is where code generation makes it rather trivial compared to handcoding it.

Wiring HTML to actions otherwise has nothing to do with SAM.
If we take a simple example, say a login panel:
<input id="username" type="text" value="username">
<input id="password" type="password" value="password">
<button class="button" id="login">Login</button>
Your handler is going to look like that (assuming the function V = S(M) is computed on the client):
$('#login').click(function() {
        var view  = document.getElementById("view") ;
        var session = $.post( "https://www.nomvc.com/actions/v1/logmein", { username: $( "#username" ).val(), password:$( "#password" ).val() } ) ;
            session
                .done(function( model ) {
                    view.innerHTML = state.render(model) ;})
                .fail( function(data) {
                    view.innerHTML = state.render({error: "server error"}) ; })
    }) ;
Jean-Jacques Dubray
@jdubray
Feb 24 2016 16:13

The State element is generating both the state representation with the knowledge of the actions. So there is no conceptual difficulty in aligning the two.

id="login"

can be generated not handcoded

bgusach
@bgusach
Feb 24 2016 16:26
@jdubray your example is fine, but I really don't think that is elegant in a general case. Let's say we have a model with some items, and for each item you want to create a button: with the IDs approach you iterate through the model, generate the HTML string, then you attach it to your DOM top root node via innerHTML and then once rendered, you iterate again through the model so that you know some IDs, fetch DOM elements by ID, and then append handlers. I really would not do that. It looks way easier just to generate the DOM nodes with createElementcalls, bind the events, and return the DOM object instead of a string. Anyway, as you have commented, this is not an architecture issue...
adonirammedeiros
@adonirammedeiros
Feb 24 2016 16:30
@gunar if my low level components know about high level components they become attached to the context and I lose component reusability. I think about components that know a little bit about each other, just to allow the composition. I looking for something like mithril (I know mithril is a framework and SAM is a pattern), hmvc or pac. I like SAM idea. I try to imagine how I can reuse components in different contexts with little to no "friction". Putting a lower level Model inside a higher level Model, can lead me to put a lower level Action inside a higher level Action and so on. Based on @jdubray example (if I understand correctly) I think the Action can be used like "public interface" of a SAM component.
Gunar C. Gessner
@gunar
Feb 24 2016 16:30
@bgusach hyperscript is very interesting, yeah. Actually, React uses event propagation ("bubbling") so it only needs to attach events to the root node. I've coded a small example
bgusach
@bgusach
Feb 24 2016 16:33
@gunar, oh that is quite neat... I never took profit of event propagation. Thanks ;)
Gunar C. Gessner
@gunar
Feb 24 2016 18:03
@adonirammedeiros I'd have to think about that.
@bgusach cool right? I never knew it myself. I've asked on twitter :P
brusand
@brusand
Feb 24 2016 18:07
For components maybe typescript and modules could help for componentisation .
Jean-Jacques Dubray
@jdubray
Feb 24 2016 19:31
@brusand let me take an example I worked on recently. 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

Jean-Jacques Dubray
@jdubray
Feb 24 2016 19:38
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\
brusand
@brusand
Feb 24 2016 19:39
Thé more i see your code thé more i am conviced .
Jean-Jacques Dubray
@jdubray
Feb 24 2016 19:41
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
Again, I don't code for a living, so I am ok if people laugh at my code
but I have been coding for the last 35 years... starting with my first commercial product at age 16 on an Apple ][
now the main menu has the same references:
home.menuItems = [{link: "#films", label: "FILMS"}
                ,{link: "#theatre", label: "THEATRE"}
                ,{link: '#gallery', label: "GALLERY"}
                ,{link: '#bio', label: "BIOGRAPHY"}
                ,{link: "#ontherun", label: "ON THE GO"}
                ,{link: "#contact", label: "CONTACT"}
To be fair, this I learned from Facebook. JSX is nice but personally I find it a bit of overhead. Of course with this kind of code you need to make sure you escape your inputs, but that's a very small price to pay for the flexibility of the code.
Jean-Jacques Dubray
@jdubray
Feb 24 2016 19:55
As I said before, I been building Model-Driven Software as far back as 1993 with my students at ESIL in Luminy, so I know a thing or two about code generation.
In terms of reuse, code generation tends to be a bit better than libraries because we can generate exactly what we need from a base. In a library you only get the base and you have to make sur the right paths are enabled to support different use cases. Code generators beat libraries any day, but you can't deploy them everywhere. HTML is DSL, that's why it works so well here.