These are chat archives for jdubray/sam

26th
May 2017
Victor Noël
@victornoel
May 26 2017 13:14
Hello :)
Things are clearer now! What really helped was in fact going back to state machines (I started from the article you referenced @jdubray just above and then read everything related in the blog ;))
Also what wasn't clear before is that in SAM the State is the View (aka State representation), or at least the view interacts with the rest of the elements of the architecture via the State. Another point is about actions: I didn't understand at first what you meant by "we need to define what is an action", now I understand there are events aka datastructure on one hand (called actions in redux and co) and there are procedures/functions (called actions in SAM or in vuex if I understood correctly).
I do think examples are good for understanding complex things, theory and abstractions are important, but at one point you need to make the reader's imagination and intuition take over for the advanced concepts to be digested and to start to make sense (this is well known in daoist philosophy for example ^^). Maybe a tutorial with the less boilerplate as possible (for example reimplementing pub/sub in the tutorial is a bad idea :) would be interesting for people to get a foot in the door, it could even include state machines definition at the beginning and then SAM would be introduced on top of that. The sam website does not even recall what is a state machine for example!
Next step: introducing this in my code and see how things unravel :)
devin ivy
@devinivy
May 26 2017 13:18
@victornoel :thumbsup:
Victor Noël
@victornoel
May 26 2017 13:39
:)
Jean-Jacques Dubray
@jdubray
May 26 2017 13:47

@victornoel the little state machine you see above allows us to create a "programming language" capable of "computing". That programming language's instructions (aka actions) are:

  • big2small
  • emptySmall
  • fillBig
    ...
    I am sure it won't be as popular as Javascript, but in the end a programming language is just that a way to build state machines, so you have to somehow find a path back to them.
    What has happened over the last 50 years or so is that we have relied on a flawed version of state machines (petri nets). Intuitively it looks correct (a graph or actions and states) but in practice that has driven programming languages to rely on three approximations:
  • actions control the end state of a system (i.e. given an initials state and an action, you know exactly where the system will be)
  • assignments are equivalent to mutation
  • there is no reason to be careful about what a "programming step" is, actions can do everything

Again, intuitively we all know that's not reasonable, that's why FP has become more popular and FRp (as a programming step) is also becoming popular (Redux, Elm,...)
We are on the right track. My only only point is to say that there is a rock-solid theory behind all this and it's not FP, effects and monads. Creating a programming model where mutation is not a primary class citizen is at best naive. It will force you to coral the effects in unnatural places. Mutation are integral part of whatever we decide a programming step is, not an afterthought of any kind, something that happens under the rug.
The genius of Dr. Lamport is that he redefined what a state machine is and that definition fixes everything. What I don't understand is why the herd just jumps on theory du jour without ever looking at what's going on.
When you realize these approximations are used everywhere and stated like that I hope you understand they are not good approximations, it doesn't matter how many billions of lines of code were written that way.
Then everyone should have an answer as to how they will address these approximations.

The part I don't like in the Elm/Redux model is that my making an action a "data structure" and the store something really dumb it's like you are putting a functional box on these three approximations, everything ends up in the reducer and then when you need to call APIs you stitch them with fancy stuff like Sagas.
It's not very complicated, but any discussion about these questions is simply impossible, OOP is dead, long live FP or FRP or whatever.
Victor Noël
@victornoel
May 26 2017 13:57
hehe, I think it's more complex than it is complicated. I have to admit something: I have a PhD in software engineering for complex/self-organising systems AND I studied mainly the question of defining domain specific languages for programming such systems. And the thing is that, EVEN with that background, I still had some hard time understanding it, because it's complex and not easy to teach :) Also I believe people are not well educated in theoretic computer science, even when it directly applies to practical computer science (I'm ashamed, but I though I knew enough of state machines before starting this discussion the other day, and yesterday I had to go back to the basics, it did me lot of good : ).
Most of my colleagues don't have the background AND can't manipulate abstractions easily (I could do the latter, the former was a bit lacking...).
So... there is still some work to do to communicate on this, and most people won't listen except if you have a killer app :P
Paolo Furini
@pfurini
May 26 2017 14:02
Hi @jdubray, regarding these last points about FP, I somewhat agree but at the same time disagree.. I'm not an FP purist (TBH I'm an FP newbie) but I think that some principles are very good indeed. The point about immutability is a strong one, if you take that as a useful principle and not a dogma. In most cases, especially when dealing with poorly architected systems, or unexperienced devs, mutations are spread everywhere, whether the state of an entity should indeed be predictable and reproducible (obviously by taking into account the side effects like the I/O etc., that in pure FP langs led to the infamous Monad term)
Jean-Jacques Dubray
@jdubray
May 26 2017 14:05
@pfurini every programming has to align with first principles. FP and the resulting immutability is just a box, it does not align with first principles (FP?) where mutation has to be a primary class citizen. The universe doesn't create a copy of itself each time something needs to change.
It is not mutations are spread everywhere it is assignments, if you make a difference between assignments and mutation you no longer need immutability.
FP is trading a problem for another (mutation for effects). It says look, we no longer have uncontrollable state mutations, but now it creates a mind bending way to deal with effects. Saying you don't need to be an FP purist is already stating that FP does not work. As I said before, the paradox with FP is that the closer you approach to purity the more dis-functional it becomes.
Victor Noël
@victornoel
May 26 2017 14:07
I think that in this discussion, there are two points of view: architecture and localised design. FP is great for the latter, but what you seem to be talking about is more about architecture, no? You can use FP inside you architecture modules but the concept of state and mutation is present at the architectural level... something like that :D (I'm not very clear)
Paolo Furini
@pfurini
May 26 2017 14:08
@victornoel More or less what I was thinking
Jean-Jacques Dubray
@jdubray
May 26 2017 14:09
You can't adopt a programming model that kinds of work 80% of the time. A programming model should work 100% of the time with short cuts/optimizations that do not compromise the programming model, they are truly optimizations, nothing breaks at the semantic level.
Victor Noël
@victornoel
May 26 2017 14:10
Quick question on the side @jdubray about the relation between the view, the state and the model. We want the state function to know the view, but not the inverse right? So if you change the view (e.g. you change the framework, or you are making views for a mobile device instead of desktop), then you need to change the state function to produce a state that can be consumed by the view. Is it correct?
Jean-Jacques Dubray
@jdubray
May 26 2017 14:10
@victornoel @pfurini no not at all, how good is a programming model is you create discontinuities as you change the point of view. SAM works at any scale:
Paolo Furini
@pfurini
May 26 2017 14:11
You can adopt the principles to be a better OOP programmer, especially if someone doesn't have the time or academic background to do a theoretical research.. I mean, Haskell and Elixir are helping me enhancing my experience through practical examples
Jean-Jacques Dubray
@jdubray
May 26 2017 14:12
@victornoel correct, the view should be as decoupled as possible. This allows for two things:
  • creating reusable view-components
  • "theming" your application, you can change the framework or the theme, (S)AM remains unchanged (State would remain unchanged if the state representation is expressed as properties which is a best practice)
Victor Noël
@victornoel
May 26 2017 14:13
@pfurini it is the responsibility of those that have this time to build patterns, framework and co that enforces the correct solutions :) I think that's why SAM exists and that's why SAM approach criticizes the way things are done in redux or similar approach.
Jean-Jacques Dubray
@jdubray
May 26 2017 14:14

you need to change the state function to produce a state that can be consumed by the view

this is not entirely true, if you express the state representation as properties, then all you have to do is make sure the signature of the view components consume the same properties (or a subset) and then you can reuse the state 100%

Paolo Furini
@pfurini
May 26 2017 14:15
BTW I agree that mutations must happen, and that the Monad approach is kinda stretchy.. In fact I prefer languages like Elixir, that takes a more pragmatic approach
Victor Noël
@victornoel
May 26 2017 14:16
@jdubray ok, I see
Jean-Jacques Dubray
@jdubray
May 26 2017 14:18
The goal of the state function is to keep the model solely focused on mutation and ignore representation entirely.
just like the action would prevent either the view or the model to translate the event into a proposal to mutate the application state. When you give the developer "assignments" they will end up doing the wrong thing, there is simply no boundary they can rely on to isolate mutation from event processing or state representation. They will couple of this code in one big ball of mud.
Victor Noël
@victornoel
May 26 2017 14:22
ok... and what about knowing the state of the application? It is fully inferred from the model at a given time, right? you even sometimes need to store some variable only for the sake of knowing the state (the example that comes to my mind is storing some kind of "request sent" flag and "response received" flag). Doesn't this make the model become oversized? Or do you have some way of externalising that, or at least compartmentalising that, depending on the current state... ?
or is that a orthogonal concern to the questions SAM is trying to solve?
Jean-Jacques Dubray
@jdubray
May 26 2017 14:24
well, that's what I was arguing earlier, if you call your APIs in the actions or the model, there is no need for these ancillary state machines. I tried a couple of weeks ago to do it with next-action but this is literally horrific.
my recommendation is that when you reach the point when you have these ancillary state machines, especially for API calls, you are most likely doing something wrong.
Victor Noël
@victornoel
May 26 2017 14:25
ok, I better understand, but what if I need to show on the view that we are in these ancillary states? For example you want a nice little spinner when the request is sent but no response arrived before. You have to store it in the model, no? since the action only present data to the model...
Jean-Jacques Dubray
@jdubray
May 26 2017 14:26
The proverbial "state" is the "page", so yes, the model keeps that: https://github.com/jdubray/startbootstrap-clean-blog/blob/master/components/menu.component.js
What you are mentioning is something that's very specific of HTML5/CSS, they are not "functional" you cannot always express V = f(M) with the way HTML5 and CSS are designed.
Personally I use a "loading..." label on the areas that are currently loading it's very easy to do that with functional HTML, but the spinner works too if you start spinning before you call the action.
With SAM you never get lost, you never have "weird" bugs that you can't understand why it is happening. Though I faced one yesterday that was kind of funny.
One of my modals didn't work properly, the backdrop remained after the modal closed. I think it is because that modal has a selector in it, but I didn't check.
Victor Noël
@victornoel
May 26 2017 14:31
For example, in the application I'm working on, storing this kind of information (in the store/model, I actually have an architecture not so far from what SAM do in the end, except for some points) is really bothering to me, there is more and more of them, and I don't use these properties to keep track of which state I am in, I only have them because I need to show them on the page. I was hoping SAM had a way of doing things that would solve this situation... but now I remember that in vuex, it seemed that you could know, as the emitter of an event (that triggers an action) when that action is finished, so in that case, this would be covered, but I'm not sure it is correct to do it like that then...
I don't see where it does say it is a chrome bug in that SO page... :)
Jean-Jacques Dubray
@jdubray
May 26 2017 14:33
In other related post they say that, anyways looking at how people tried to resolved it, I ended up making that call that lead to a runtime error (because I didn't use JQuery for it):
image.png
Victor Noël
@victornoel
May 26 2017 14:33
^^
Jean-Jacques Dubray
@jdubray
May 26 2017 14:34
and guess what that after that call the backdrop disappeared, I removed the call and the backdrop stayed :-)
devin ivy
@devinivy
May 26 2017 14:35
@jdubray okay, imagine i click to "save" a post ten times in succession. using SAM, how would you implement cancellation of all in-flight saves upon each click?
Jean-Jacques Dubray
@jdubray
May 26 2017 14:36
In any case, bootstrap modals are a great example where "functional HTML" is the way to go. I have hope that one day the spinner will work that way, in the meantime you can do that: https://github.com/jdubray/sam-samples/tree/master/react-spinner (this is not react specific)
devin ivy
@devinivy
May 26 2017 14:36
action hang-back in SAFE only seems to not require an ancillary state machine because it's a simpler sort of "race" for the in-flight actions.
but generally there are all sorts of ways you might want to orchestrate actions. either you keep track of that state in the store via some little state machine, or you keep state somewhere else (e.g. hidden in a closure).
Jean-Jacques Dubray
@jdubray
May 26 2017 14:37
@devinivy as I mentioned before cancellation is trivial in SAM, you can adopt an approach similar to SAM-SAFE (State-Action Fabric)
https://github.com/jdubray/sam-safe
devin ivy
@devinivy
May 26 2017 14:38
in SAFE it's different– hang-back is a race in that case.
Jean-Jacques Dubray
@jdubray
May 26 2017 14:38
yes, but you can still implement specific behavior using a similar approach, SAFE is generic.
API orchestration is a different beast altogether,
devin ivy
@devinivy
May 26 2017 14:39
not API orchestration– just mediation of actions. i.e. the functionality you can achieve with Rx or sagas. it doesn't seem like SAFE presents a generic solution to that.
Jean-Jacques Dubray
@jdubray
May 26 2017 14:39
that is where SAM started, I was looking for an orchestration capability that could be written in Java and Javascript, as opposed to BPEL (writing the equivalent of BPEL in Java is just virtually impossible)
That's what I mean that you programming model has to be ubiquitous, you can only allow for optimization, not breaking its semantics.
Victor Noël
@victornoel
May 26 2017 14:41
@devinivy if you manage to instantiate SAM using ngrx/store and ngrx/effects (and I feel like it is doable, but with some discipline, I'm still thinking on it : ), then this problem is easy to solve because actions are effects, and effect are implemented using observable. With observables it is possible to cancel previously started sub-observables (such as an API call) if another is started using a switchMap operator (basically this is a reaction to an event that triggers an API call returning an observable, and if another same event is triggered, then the first observable is cancelled and a new one is created). Not sure I'm totally clear
devin ivy
@devinivy
May 26 2017 14:43
@victornoel i agree rx would make this simple, but i think @jdubray would take issue with it because there would be statefulness there not living in the model, but instead in the plumbing of your observables.
Victor Noël
@victornoel
May 26 2017 14:43
yes but maybe this state is only the state of ancillary state machine, and that would be..ok ? :D (winging it ^^)
devin ivy
@devinivy
May 26 2017 14:43
haha ;D
i personally think that state is okay to live elsewhere providing that it lives in a well-established library like rx.
Jean-Jacques Dubray
@jdubray
May 26 2017 14:44
As long as the states are independent, i.e. the model does not need to know about it to make it's decisions, it's ok
it's the same as parent/child. The plot thickens when the model needs that state...
devin ivy
@devinivy
May 26 2017 14:44
interesting
Victor Noël
@victornoel
May 26 2017 14:44
yep
devin ivy
@devinivy
May 26 2017 14:44
so what does that mean about your thoughts on sagas?
Jean-Jacques Dubray
@jdubray
May 26 2017 14:45
The advantage of parent/child is that the child can report to the parent at any time (without any incidence on the -parent- view)
devin ivy
@devinivy
May 26 2017 14:45
my understanding is that it moved state out of the "single store"
which you didn't like. rx would be doing the same thing.
Jean-Jacques Dubray
@jdubray
May 26 2017 14:45
when the state is embedded in exotic semantics like generators or streams or whatever, you don't have that liberty
Victor Noël
@victornoel
May 26 2017 14:46
so you mean the only problem is that once you start hiding the state in some rx thing, then you are locked in this situation and if in the future you need that state, you have to change everything?
Jean-Jacques Dubray
@jdubray
May 26 2017 14:46
yes...
devin ivy
@devinivy
May 26 2017 14:47
but isn't the alternative precisely keeping nasty ancillary state machines in the model.
Jean-Jacques Dubray
@jdubray
May 26 2017 14:47
in a parent/child relationship, any change in the child can be immediately reported to the parent, you have a very natural synchronization mechanism
@devinivy yes, you can do that too, but that's clutter. I don't think it is scalable.

I was hoping SAM had a way of doing things that would solve this situation...

@victornoel I don't understand your question

devin ivy
@devinivy
May 26 2017 14:48
i don't see what exists in between those two options. how does the child/parent business apply to this problem? it seems like a concrete enough thing to demonstrate.
Victor Noël
@victornoel
May 26 2017 14:49
@jdubray wasn't really a question... the present discussion is more adequately answering my wonders now :)
I agree with @devinivy: there seems to be two solutions, either hide the ancillary state outside of the model, and then it is dangerous in terms of maintenance, and store the ancillary state in the model, but then it's clutter and not scalable...
did we miss somehting there?
Jean-Jacques Dubray
@jdubray
May 26 2017 14:53
If it relates to APIs, please remember that you can avoid both by calling the APIs in the actions (queries) or model (create, update, delete)
Victor Noël
@victornoel
May 26 2017 14:53
I was starting from the assumption the call would be done in the action...
I'm lost ^^
Jean-Jacques Dubray
@jdubray
May 26 2017 14:53
If you need a "cancel" mechanism, SAFE provides a generic one (albeit not universal) which can be adapted.
For me that was the biggest value that SAM brought to front-end architecture
compared to Redux/Flux or Elm.
@victornoel sorry, you can actually make the call in the action before the model knows about it. hence no need to maintain state in the model
I use that approach 90% of the time
Jean-Jacques Dubray
@jdubray
May 26 2017 15:04
You can even do simple orchestrations until you present the proposal to the model. If you need more complex (stateful) orchestrations or cancellable API call, you'll need to maintain the state somewhere (child instance, ancillary state machines in the main model...). I just don't like to manage state where it cannot be accessed or propagated to the main model.
Victor Noël
@victornoel
May 26 2017 15:05
@jdubray what I am missing is when you say "child instance" and before you talked of paent-child interaction. I dont understand what you are talking about with these terms...
Marcus Feitoza
@mfeitoza
May 26 2017 15:06

@jdubray
what do you mean ancillary state?

tree = {present, state}
tree.model1 = {present, state}
tree.model2 = {present, state}

I have a single tree so ancillary state will be model1.state and model2.state correct?

Victor Noël
@victornoel
May 26 2017 15:10
@mfeitoza from what I understood, ancillary state are states of an ancillary state machine. And an ancillary state machine is a state machine that exists only temporarily, for example just for the time of an action or a set of action (in that case, it must be stored in the model)
something like that :)
Marcus Feitoza
@mfeitoza
May 26 2017 15:11
I got, thank you.
Victor Noël
@victornoel
May 26 2017 15:12
(wait for confirmation from @jdubray though, because I may be mistaken!)
Jean-Jacques Dubray
@jdubray
May 26 2017 15:17
@victornoel this is an example of parent child (here client/server but works in any topology)
image.png
@mfeitoza ancillary state is when you need to keep some state in the model that is relevant to something ancillary to your application (such as calling an API).
Victor Noël
@victornoel
May 26 2017 15:19
@jdubray ok, I better understand the discussion now. so your recommendation is that usually, it's the best way to things by having some kind of child SAM that exists temporarily (for example during an orchestration of API calls)?
Jean-Jacques Dubray
@jdubray
May 26 2017 15:19
Any kind of effect-based approach would lead to an ancillary state machine in your model (declarative effects).
@victornoel yes, complex orchestration would be better implemented in a child SAM instance.
What I find really cool about SAM is the composability
image.png
an action can present to more than one model (sorry, wow!)
Victor Noël
@victornoel
May 26 2017 15:20
lol
Jean-Jacques Dubray
@jdubray
May 26 2017 15:21
third party actions can present to your model too (sorry again, wow!)
image.png
This kind of topology is unheard of in classical application architecture.
(MVC)
There is also the many-to-many relationship between actions and acceptors (the building blocks of the model) that I use all the time.
It's very limiting to have the action "call" something in the model (say like vuex). By passing a proposal you allow the model to operate like a pipeline and have multiple acceptors respond to the proposal.
devin ivy
@devinivy
May 26 2017 15:24
do you think in that case you'd almost definitely want another SAM loop on the client for optimistic updates?
Jean-Jacques Dubray
@jdubray
May 26 2017 15:25
yes, that works well. In a lot of apps (say banking, shopping,..) the user prefers that they can continue only when the previous activity has completed or has a reasonable chance to complete as expected (you can always compensate anything).
Optimistic updates are a bit unsettling in terms of UX when something goes wrong, because your expectation was, since you can continue doing something else, everything was well. When you get an error message while working on the next activity it's a bit odd.
Optimistic updates is more for a "fire and forget" pattern
Marcus Feitoza
@mfeitoza
May 26 2017 15:37

Awesome, SAM (of course you) is pushing me to understand and think more deeply.

You claim to have one action/intent per step right? Because could generate an incorrect state.
In the case of parent/child, I can fire at same time or not an action in parent, child1 and child2?

Jean-Jacques Dubray
@jdubray
May 26 2017 15:40
yes, that's the key, action/mutation/state representation need to occur before you can process another action.
Actions are functionally composable A = f1(f2(f3(event))), but no mutation occurs during the functional composition.
that is not part of the programming model, just an optimization of the code.
In other words, it's not because functional composition is possible that it breaks the programming model, it's orthogonal, SAM does not include/use/rely on functional composition in its semantics (say unlike FP).
@mfeitoza I am really not looking for any kind of praise, I'd rather have a good discussion where I am proven wrong or fuzzy instead. Our industry too often is incapable of these discussions.
Yet, they bring so much value to everyone if for once we could have such culture, we all have limitations (and I have so many :-(), we can only make progress by having these open objective discussions, painfully comparing concepts in non trivial situations.
Marcus Feitoza
@mfeitoza
May 26 2017 15:46
Thank you!
I understand, but is really good have discussions with you.
Jean-Jacques Dubray
@jdubray
May 26 2017 15:57
same here, I really enjoy having all these discussions.