These are chat archives for jdubray/sam

6th
Sep 2016
Riccardo
@riccardoferretti
Sep 06 2016 08:39

@jdubray I have been thinking about the following and I would like to hear your thoughts on it.
Say I have a material design style button. In theory, if all state were to be exposed publicly, every aspect of such button would be public. For example the color of the button, the text of the button, but also whether the button is in hover state, or the state of the ripple effect occurring after .3s after I clicked the button at {x:2, y:7}, etc..
The last two seem to me like “internal” state of the button. That is, from the consumer of the button, I don’t care if the ripple is half way through. In fact, I don’t want to know, as it makes creating/managing such simple component much more cumbersome.
Possibly more important, I need to manage such state (e.g. onMouseIn I need to set the isHovered flag to true, and so on).
We always have implicit state in any UI component (e.g. we don’t change the isHovered flag on a link, we don’t switch it on on mouse in and mouse out), we have some way of defining such behavior (e.g. the hover color in css), and the system automatically manage it for us (e.g. onMouseIn onMouseOut).
When we use “standard” components, we are implicitly taking advantage of that.
That can also mean we can’t re-create such state (e.g. you can’t time travel to when the ripple effect of the button was 2/3rds done), but for transient state (like the mouse hover or the ripple effect) we are happy to “lose” that.

Now, I built a button made up of two images, when not pressed and when pressed.
From a point of view of the client of the button I am only interested in the click event, but because I need to manage its internal state, now the client is forced to attach actions to all all the button’s events, and forward them through the main loop (e.g. I want it’s appearance to change on mouse down, so that action has to go through the loop).
The alternative would be to have a stateful component, that holds some internal, transient state, so that its clients don’t need to “be exposed” to it.

Sorry for the long context, and I hope this makes sense - what’s your take on it? would you manage that as a child state machine? am I missing something?

Jean-Jacques Dubray
@jdubray
Sep 06 2016 12:06
The way to think about SAM is in terms of events: event / new application state / new state representation / nap
There can be lots of things that happen outside of SAM's control, there is no reason for SAM to handle the whole state if these states are ancillary to the application state. You simply need to decide how that state alignment occurs. SAM is pretty basic when it comes to state alignment:
  • you can rerender the view component (alignment by design)
  • you can pass new props to the view component (alignment by event)
  • you can pass a function (alignment by orchestration)
Of course, you are a bit constrained by the idiosyncrasies of HTML5/CSS3, you can only work around them.
Jean-Jacques Dubray
@jdubray
Sep 06 2016 12:19
I still think that functional HTML is the way to go V = f(M), but after working with Angular2, it looks like it can also be implemented with property subscriptions. It is strictly equivalent, you don't have to throw away the entire view to render a new state representation. Direct DOM manipulations are strictly forbidden. You don't want one component to manipulate another, but it is irrelevant how the DOM is rendered, as long as you follow a V = f(M) approach.
You have to strike a balance between the size of application state and its fragmentation. This also depend on event concurrency. The general assumption behind SAM is that it's ok/possible/desirable to serialize the processing of events. It may not always be true. It's just a pattern... not the rule of law.
Riccardo
@riccardoferretti
Sep 06 2016 12:28
thanks a lot, that’s really interesting. I really like the various alignments you described above, they hadn’t occurred to me.
Riccardo
@riccardoferretti
Sep 06 2016 12:34
to clarify, when you say V=f(M), are you implying that the stateful approach would be incorrect? or in this case of the example M could actually be the internal state (not visible to the component’s clients) of the component + its external state
and, more specifically, if you had to implement the same thing what would your approach be :)
Jean-Jacques Dubray
@jdubray
Sep 06 2016 13:19

Not exactly,

V=f(M), are you implying that the stateful approach would be incorrect?

= is a state alignment operator, not equality, if I try to represent it symbolically, it is the state alignment that always need to be expressed as a function of the model:

V     = f(M)
V=f(      M)
V += f(M)

The implications are that:

  • the state local to the view is inaccessible to the model, and vice versa
  • the state alignment occurs at a specific point in time controlled by the model
  • the state alignment happens as a unit of work

That's really what V = f(M) means

Fred Daoud
@foxdonut
Sep 06 2016 13:52
@riccardoferretti if I may add to the discussion, I wrote an example with Meiosis of components that manage their own state. The "temperature" components manage their own state, that would be the equivalent of the state of your button that you want to manage. So the component has its own "receive" function (equivalent to model.present) and manages only the state that it cares about (value and units). At the same time, you have access to these values outside of the component because the state is in the single root model (at store.temperature.air and store.temperature.water). Outside of the component is where you "nest" them at the desired places in the single root model, but the components don't need to know.
I am also working on an example with a modal dialog, I'll post it when it is ready. In both cases, the components manage their internal state but because it is nevertheless part of the single root model, you still have V=f(M) and you can still time-travel through these states.
devin ivy
@devinivy
Sep 06 2016 14:49
i also think there are times that it's worthwhile (ergonomically) to let components keep their own internal state. like you said, transient state is okay to lose. but also– technically something like button "hover" is computed from the state of your cursor! you should not duplicate that state into the model since it can be computed from the state of the mouse.
you would never render the app with a button in a hover state if the cursor were not hovering over it.
Riccardo
@riccardoferretti
Sep 06 2016 14:51
thanks @devinivy and @foxdonut, I was actually wondering how I would have done that in meiosis
devin ivy
@devinivy
Sep 06 2016 14:52
cheers!
Riccardo
@riccardoferretti
Sep 06 2016 14:52
( @jdubray I will admit I didn’t quite grasp that :) )
devin ivy
@devinivy
Sep 06 2016 14:57
my favorite example of keeping internal state is for forms that are synced with the model/state when the model is doing validation. (@foxdonut and i chatted about this quite a bit.) my approach is for the form to display whatever value the user types and propose a change for that value to the model. that proposal might be rejected (if it fails validation) but the form should still display what the user typed. when the internal value and the value in the app state don't match, you know the form field is invalid.
devin ivy
@devinivy
Sep 06 2016 15:05

@jdubray
i like this,

The implications are that:

  • the state local to the view is inaccessible to the model, and vice versa
  • the state alignment occurs at a specific point in time controlled by the model
  • the state alignment happens as a unit of work

That's really what V = f(M) means

Vincent Jo
@chiwoojo
Sep 06 2016 22:08
Hi JJ I was wondering if actions could be allowed to read values from the model?
Or does that defeat the purpose
Jean-Jacques Dubray
@jdubray
Sep 06 2016 22:10
@chiwoojo no, that's an anti-pattern, what you want to do is pass the necessary information to the view via the state representation. It will then be passed to action via the event/intent
Do you have a specific example in mind?