These are chat archives for jdubray/sam

3rd
May 2016
Jean-Jacques Dubray
@jdubray
May 03 2016 02:08
very nice, I can understand why you would need a dedicated architecture for that kind of solution. Not sure SAM would work well in this kind of architecture. The principle stand but you might want to process series of actions than individual ones. Thinks like SAM's cancellation could be of interest to you.
Roman NL
@rnique
May 03 2016 03:41
What is a state? Could it be represented by a promise wating to be consulted by an arbitrary client (function) allowed to do so?
Jean-Jacques Dubray
@jdubray
May 03 2016 03:50

The State function does two things:

  • renders/computes the view
  • invokes the next-action predicate which evaluate if there is an automatic action that needs to be executed in the current (control) state.

People traditionally view the application state as a list of key value pairs, but that's not enough, given the list of property values, the "state" of the system will be derived (think about what it takes to decide whether a car is in a "started" state) and control which actions are enabled in that state and if there are any automatic actions associated to it.

IMHO, you can't speak about "application state" without having both the model and the state function. The same model could have several state functions for different systems.

In theory, yes, you could view a control state as a promise, which once reached would trigger a rendering and next-action.
Roman NL
@rnique
May 03 2016 04:02
Do you think it is possible to describe (rather implement) a state graph by chaining/nesting/forking/joining promises?
Jean-Jacques Dubray
@jdubray
May 03 2016 04:12
I would discourage against building a state graph. I know that this is the traditional view of State Machines, but IMHO, the state graph is observed. IMHO, an action proposes values to the Model which accepts them, it is then the State function which computes which "state" you are in, it is not decided by the action a priori. Of course you have a general idea of what state will come next, but what I learned from TLA+ is that this traditional semantics may not be the best way to designing state machines, it is not general enough, it is not wrong, but there is a better design. You can look at section 4 of this paper, or if you have time read it entirely, it's very interesting.
I am not familiar enough with Promises and Observables to say if that's the best way, but when a "state" evaluates to true (the model property values are such that you are in that state), then the promise returns a value (e.g. true), which can be used to trigger rendering and next-action. I am not sure how this compares to doing the evaluations in the State function and triggering rendering/next-action from there.
Roman NL
@rnique
May 03 2016 04:16
Thank you very much, I will surely read that paper. Right now I am reseraching the "theory" part rather than "implementation" part of SAM and similar patterns, in order to get better idea if their potential and possible applications
Jean-Jacques Dubray
@jdubray
May 03 2016 04:16
TLA+ is a real paradigm shift, IMHO, because it align the semantics of State Machines with the way we write code.
That's what always bothered me in Petri Nets (graphs of actions and states), it always felt very painful to code, unlike TLA+
Roman NL
@rnique
May 03 2016 04:21
So TLA+ was the idea that "opened your mind" to SAM? Particularly, the paper that you just shared with me? Or would you recommend any other source, as to understand your solution proposal? Couldn't the State part of your pattern become the bottleneck when scaling horizontally a distributed system?
Jean-Jacques Dubray
@jdubray
May 03 2016 04:25
yes, that paper is a great start. Initially I was turned off by the lack of "state" semantics in TLA+. Dr Lamport uses a specific variable, pc (program counter), to store "state" values, but ... when you think of it as a, perhaps, the, definition of state machines, then it changes your perspective entirely. For me that moment was when I realized that TLA+ was no longer graph based. Intuitively a graph based state machines seems appealing, but you have to leave that idea behind. The graph is observed, not specified.
Then there are numerous papers and tutorials.
Jean-Jacques Dubray
@jdubray
May 03 2016 04:32
In particular, you can now decide if the system reaches undesirable states (or desirable ones), because now you compute the next-state from the model key property values, you do not rely on telling you if that action is triggered you automatically reach state Sa. For me that was the big paradigm shift
Stardrive Engineering
@HighOnDrive
May 03 2016 04:33
" Intuitively a graph based state machines seems appealing, but you have to leave that idea behind." Really?
Jean-Jacques Dubray
@jdubray
May 03 2016 04:33
When you think of it's its logical, you don't know a priori how a system is going to respond to an action. A friend of mine told me an analogy that I found explains well the concept: say you apply the same force to two cups, a paper cup and a ceramic cup. In one case the cup is crushed in the other it is unchanged. It is the system which decides the resulting state, not the action.
@HighOnDrive yes, absolutely
Stardrive Engineering
@HighOnDrive
May 03 2016 04:34
What do you mean by "The graph is observed, not specified." ?
Jean-Jacques Dubray
@jdubray
May 03 2016 04:35
The graph of State-Action/Transition is a result of the computation, not a specification a priori. You specify actions (values presented to the model), you specify the model (how it accepts presented values), then you specify how states are derived from model property values. When you apply an action you don't know a priori which state you will end up in, you can only observe the resulting state
this is a huge paradigm shift
that is why TLA+ is so fundamental to computer science. State machines as we know them were ignored, precisely because they do not work "well enough".
When you specify a graph of States-Action/Transitions, then it is the action that decides of the resulting state, you have 'no' choice
It works for a certain class of systems (namely where models accepts all values presented to them), but it does not work in real life, because there are not that many systems like that.
Roman NL
@rnique
May 03 2016 04:39
So when scaling horizontally SAM pattern, each machine would compute its own state, then they would need to sync or check each others state?
Jean-Jacques Dubray
@jdubray
May 03 2016 04:39
that's why I could never understand @brucou position on TLA+, as you know he went on straight back to more traditional state machines.
@rnique I don't understand your question. There is only one application state (say per user). I am building an AWS Lambda / DynamoDB implementation to show just that. It's almost ready.
SAM offers different architectures, for instance you can implement the actions on the server and the Model+State on the client
Roman NL
@rnique
May 03 2016 04:43
I mean, if one application is distributed among severeal machines working in parallel, one machine may fail, but we dont want the overall state to become "Failed", despite one machine would have its state "Failed"
I think AWS Lambda would be a great leverage for implemementing this kind of patterns
Jean-Jacques Dubray
@jdubray
May 03 2016 04:45
I don't understand your scenario, if "failed" is a state, then other systems would know of it and align their state accordingly. Distributed systems implement inter-actions (and protocols) to do just that, align their state.
Yes, I agree, the Lambda implementation is almost ready, I am debugging it. The application state (per user or not) is stored in DynamoDB. The performance of both combined is amazing.
SAM is totally isomorphic so you can redeploy the elements of the pattern even after you finished coding them.
Stardrive Engineering
@HighOnDrive
May 03 2016 05:01

That could all be fine, I'm zooming out a bit in my view of what the SAM/MVI pattern could actually be then. Why not see the SAM stages as functions (processors instead of drivers) that flow into each other? We already know that they are the stages of the reactive flow, right?

These staged processors are then sequenced together in your app or per component then re-purposed to act according to directives. The directives are grouped into states in a state machine definition. The activated state has it's directives applied to each of the staged processors to re-purpose the whole flow.

The processors can still take into account all that is important to TLA+ except together with the states of grouped directives you have the groundwork for a very versatile and flexible feature driven architecture. The whole concept of what CycleJS calls sources and sinks is also greatly expanded :+1:

Stardrive Engineering
@HighOnDrive
May 03 2016 05:06
When I say "SAM/MVI pattern" I just mean to include all the different patterns out there. It's the reactive loop that matters most and then SAM is proposing to be the best way to break it into stages. I'm not disagreeing as long as the stages can be made flexible enough to accomplish what a app needs to do :smile:
Jean-Jacques Dubray
@jdubray
May 03 2016 05:08
sure, but the single state tree is essential, you can logically and physically compose independent parent/child SAM instances, but you can't distribute the application state of one instance. I think you can decompose the stages relatively flexibly but you cannot run many in parallel, I don't see how this could work.
The parent/child works by instantiating a child instance in a parent state, the child can invoke an action of the parent which will lead to a new state and end the lifecycle of the child.
Stardrive Engineering
@HighOnDrive
May 03 2016 05:13
I follow most of that but wonder if what you are calling "parallel" I'm thinking of as 're-purposing' instead?
Roman NL
@rnique
May 03 2016 05:17
Why single state tree is essential? I was thinking of possibility of allowing the application to see neighbour instances and infrering the state from there. Or letting the application to know my immediate parents and children, or maybe the relevant elements in the tree, necessary to infer the state.
Jean-Jacques Dubray
@jdubray
May 03 2016 05:19
I believe the single state tree is not negotiable, because it is necessary to accept the values and compute the state. The pattern is also "step-based", it is not designed for concurrency (of course every user will have a single state tree, I am not talking about that kind of concurrency).
There is this notion of "next-state" that must be precisely derived, if you scatter the application state and allow the different branches to update in parallel, I believe nothing will work.
Even in parent/child, it would be preferable to keep the parent in a given state, otherwise, the child state might change.
Stardrive Engineering
@HighOnDrive
May 03 2016 05:36

Hope it was okay convey a bit of how I see SAM/MVI much like the lifecycle stages of the reactive loop. I was recently looking at how the Atom IDE defines it's plugins to scale the core loop.

Interestingly it is in great part done via a group of directives, which they call a package and activate(state) is the one required function. Yep, they got it :clap:

Jean-Jacques Dubray
@jdubray
May 03 2016 12:03
Everything is ok, I am not trying to round up followers. I don't make any money each time someone spells or uses TLA+ (nor Dr. Lamport). We are obviously dealing with reasonably complex questions and an open mind has proven generally effective at answering a number of them. If someone finds a better interpretation of TLA+ or something even better than TLA+, I'll adopt it in a heartbeat.
devin ivy
@devinivy
May 03 2016 12:33
@jdubray have you considered what it could mean to put parts of SAM in a web worker? also re: the github/redux discussion, i think providing an example of a SAM app being modularized would be very useful for the folks over there, even if it's a completely contrived example.
i think that mostly means having multiple acceptors.
@HighOnDrive can you link to a nice starting place (in the code) to look at Atom IDE?
i would be interested to see how they scale the loop as well.
weepy
@weepy
May 03 2016 12:51
I'd love to see an example of a Sam app being modularised
Jean-Jacques Dubray
@jdubray
May 03 2016 13:35

@devinivy but there are already many modular designs for instance the TODOMVC: https://github.com/jdubray/sam-samples/tree/master/todomvc-app/mods

It can't be more decoupled. The view components are 100% decoupled from the app (theme.js) they know absolutely nothing about the app, the wiring to the action is done by the S() function.

All the elements are wired separated here

@highondrive yes, I tried to google Atom IDE but could not find a reference to what you are talking about.
devin ivy
@devinivy
May 03 2016 13:41
@jdubray that's a different type of factoring than what i'm thinking of. i'm talking about composing slices of (actions, state, nap, ...). imagine two teams writing different corners of an application that eventually get composed together.
Jean-Jacques Dubray
@jdubray
May 03 2016 13:44

well, for me that's the super advantage of SAM is that actions for instance are "app specific" or even "domain specific". They are completely self standing, can even be built and hosted by 3rd parties.

The problem is that Redux tend to move them to the reducer, coupling "app logic" with more "orthogonal" model logic.

Imagine you are building a new product for a new country. The action will validate that the address is from that country, the last thing you want is for the model to know about app specific rules.

The theme is also 100% decoupled from the app, or the way the model is rendered (State function) is also 100% decoupled from the model.
So you can can have an "enterprise team" working on the model making sure no "app" is breaking cross-apps rules and you can have app developers building actions/state/nap, then you can have designers building theme components without knowledge of the app
To be honest this is the highest level of decoupling I have see in a front-end architecture. I am not sure what's left to decouple
devin ivy
@devinivy
May 03 2016 13:47
that's not really the type of factoring i'm thinking of.
that's talking about different teams working on the model or the theme, etc.
i'm talking about a team working on "a little bit of everything"
Jean-Jacques Dubray
@jdubray
May 03 2016 13:48
Yes, I understand, but the "vertical" slice model is actually the problem I have tried to solve. I have seen big project collapse one slice at a time.
devin ivy
@devinivy
May 03 2016 13:48
as a contrived example, imagine composing two separate SAM applications.
Jean-Jacques Dubray
@jdubray
May 03 2016 13:48
The composition is precisely at the "state machine level"
with a graph of states / actions a team can easily work on a new action / state without interfering with the work of others.
However it is better if a single team works on the model
It's not a good idea to "slice" the model
devin ivy
@devinivy
May 03 2016 13:50

still, i don't see any tools to do this,

with a graph of states / actions a team can easily work on a new action / state without interfering with the work of others.

Jean-Jacques Dubray
@jdubray
May 03 2016 13:50
Again, if you ask me that is the right way to think about composing app.
You just need to graft the entry action from the child app into the parent app (think of it as a menu item, link or button somewhere) that moves the model in a state when you enter the child app
If the child app can have an independent model that works even better (e.g. a wizard).
devin ivy
@devinivy
May 03 2016 13:54
see how this flux app is split into modules? this is more what i'm talking about. https://github.com/home-assistant/home-assistant-js/tree/master/src/modules
there's code that composes those modules together into a single app.
Jean-Jacques Dubray
@jdubray
May 03 2016 13:55
You can't arbitrarily compose things you have to work with the seams of the app logic
Sorry, I don't see the light, connecting "view" and "Model" such as the "view-store" https://github.com/home-assistant/home-assistant-js/blob/master/src/modules/view/stores/current-view-store.js
is the wrong factoring.
Jean-Jacques Dubray
@jdubray
May 03 2016 14:00
Again, if you can carve independent models / store you'll be able to compose SAM in a parent/child fashion which is desirable. They seem to be doing the same thing. There is no such a thing as a "slice" in SAM, the slice is the problem, I know that's why MVC is so popular, because you can always add a new slice
MVC induces a slow death, a death by a 1000 cuts (slices)
MVC creates runaway systems until the cost of maintenance forces a complete rewrite.
This is true of any MVx architecture. The problem is the coupling between the view and the model, that's why when I designed SAM I look for as much decoupling as I could, but as such it requires a slightly different organization of the code, it is by design that you cannot add a "slice".
devin ivy
@devinivy
May 03 2016 14:03
i'm not proposing the entire architecture or factoring of that project. also, that app surely isn't MVC. it's important to redux folk to understand how a medium-sized app would be built. redux has combineReducers() what might SAM have? this could be as simple as creating a system that has multiple acceptors. or a system that has the right "glue" to allow for "parent/child" as you mentioned.
Jean-Jacques Dubray
@jdubray
May 03 2016 14:06
Redux has become a master at selling a library for every one line of code you would otherwise to achieve the same thing.
Really? you need a library to decompose a function?
{
  reducer1: ...
  reducer2: ...
}
devin ivy
@devinivy
May 03 2016 14:07
no, not necessarily. nonetheless, it needs to be demonstrated that the pattern allows for such a thing.
Jean-Jacques Dubray
@jdubray
May 03 2016 14:08
If the models are truly independent, I recommend decomposing as parent child. "combineReducer" is again the wrong factoring because the point of the acceptor is too look holistically when accepting the value
Redux is warped by the fact that the "true" actions are inside the reducer
so you need a decomposition to make that manageable
devin ivy
@devinivy
May 03 2016 14:08
i just mean, what's analogous to combineReducers()
Jean-Jacques Dubray
@jdubray
May 03 2016 14:09
In SAM actions are outside the model, so you never need that kind of decomposition
Again, actions are individual entities, SAM doesn't coral them in a big switch statement
The accpetor's code (model) is far more compact because it's very close to CRUD
and again that code needs to look holistically.
devin ivy
@devinivy
May 03 2016 14:10

I recommend decomposing as parent child

what would this look like?

Jean-Jacques Dubray
@jdubray
May 03 2016 14:11
You build a SAM instance for each, completely independently of each other, and when you wire the entry / exit into/from the child into the parent.
If you look at the TODOMVC model, it is decomposed into three elements: https://github.com/jdubray/sam-samples/blob/master/todomvc-app/mods/model.js
Jean-Jacques Dubray
@jdubray
May 03 2016 14:27
but that kind of logic cannot be decomposed in slices or "combined", again, architecture comes first, operating model second. You can't just say I want an architecture to fit my operating model, or the primary concern of my architecture is "testability".
Jean-Jacques Dubray
@jdubray
May 03 2016 16:15
Fred Daoud
@foxdonut
May 03 2016 17:14
@jdubray : would Vue be compatible with SAM?
Jean-Jacques Dubray
@jdubray
May 03 2016 17:18
yes, there is no reason, @msolovyov has built a vue.js code sample. It looks like v2's API is not that different from V1, so I am expecting it would be easy to migrate.
Michael Solovyov
@msolovyov
May 03 2016 18:09
I'll have to give v2 a try but don't see why not
Only thing that's really different from the user perspective is that filters are mostly gone
Michael Solovyov
@msolovyov
May 03 2016 18:19
I really like that decoupled todo mvc example btw @jdubray
Jean-Jacques Dubray
@jdubray
May 03 2016 19:30
thanks, it proves that you can truly create UI components that know nothing about the app, I have not seen too much framework that are capable of that!
Jean-Jacques Dubray
@jdubray
May 03 2016 21:10

It could well be that Vue becomes my favourite way to implement SAM...

You can even embed render functions in your templates using the special <render> tag! The best of both worlds, in the same framework.

Vue just removed one of the biggest issues I had with templates (their DSL)
Stardrive Engineering
@HighOnDrive
May 03 2016 21:17
@devinivy The Atom Flight Manual delves into creating plugins and the Config API is central as well. Code for specific plugins can be accessed directly through their cards in Atom Preferences.
Stardrive Engineering
@HighOnDrive
May 03 2016 21:49

Breaking it down I see three fundamental levels that would be great to synergize into working a foundation:

1) The reactive loop
2) The stages of activities in the reactive loop
3) The plugin system for a reactive app

The first is essentially the FRP or RxJS paradigm shift hitting the JS world with full force. One can use RxJS or other alternative library as is or make an opinionated locked down system out of it like CycleJS. IMHO, CycleJS has not figured it all out yet, I vote to just use RxJS or a general library like xstream.

The second is the evolution of MVC, the present popular forms being Redux and MVI and then the wisdom of SAM. Stages here can be general yet might also include ones specific for a given app.

The third concerns itself with how to scale the first and second. Here there are many approaches like combining reducers, boxing it all into components or even more dogmatic proposals like the drivers in CycleJS.

Looking at today's comments on cycle-core it is evident that there is still a great struggle going on to take apps past the simple demos they still have to date. There is also still endless debate about state, reflecting a paranoia where it is wrongly acknowledged that if there is a state-driver then all business logic would be assumed to be there so there would be nothing for CycleJS components to do. There is something a bit off in that reasoning for sure.

I believe there is a better way. One that stages the reactive loop and re-purposes the stages through plugins. CycleJS drivers are a very limited way to approach the required scaling and generally have nothing much to do with what users most care about, being features. They also do not help to focus developers on what an app should deliver, again being features.

Feature Driven Development (FDD) was always an approach I liked and I think there is a new opportunity to apply it's wisdom. I've done this in my solution and also see that Atom has as well, something to look into further I'm sure.

Stardrive Engineering
@HighOnDrive
May 03 2016 21:54
@jdubray "Again, actions are individual entities, SAM doesn't coral them in a big switch statement". This is where a plugin solution comes into play :sparkles: