These are chat archives for jdubray/sam

22nd
Jul 2017
Slađan Ristić
@sladiri
Jul 22 2017 08:32

... but the State-Action behavior of state machines will make the code impossible to write. SAM suggests a new (heretic) behavior, the State-Action-Model behavior... Then each part of your code can reason cleanly about their own role.

Thanks for pointing it out again, that is what I missed.

Slađan Ristić
@sladiri
Jul 22 2017 11:32

@jdubray ... I will also refactor my initial decision to try to orchestrate complex queries with NAP which was also a very stupid decision. I just wanted to do like the Redux/Elm guys, which I believe people start seeing how broken that is

Do you mean setting inProgress=true in model, and doing an API call as automatic action (NAP)?

Jean-Jacques Dubray
@jdubray
Jul 22 2017 12:21
yes
this makes no sense, pure Cargo cult
Slađan Ristić
@sladiri
Jul 22 2017 12:51
:thumbsup: So you would use a compound action, which calls action showSpinner one then callAPI? Wouldn't that mean that inside a SAM SAFE container, you would block any other action, while this is in progress? Otherwise, another proposal would cause this to be stale and rejected.
Or would you just call both actions independently in sequence, not as one compound action?
Jean-Jacques Dubray
@jdubray
Jul 22 2017 13:15
You can actually present multiple times. You can present this proposal {dataIsLoading: true} then make the API call, then present the results of the proposal with { ... dataIsLoading: false}. SAFE is not about blocking "any" action, it's really about having the logic State -> allowed actions. When you are in the state "dataIsLoading", you could decide what to do if a new action is invoked. In general you can run queries in parallel. If there are any ordering issues (say you want to show Results2 only after Results1 are available) you can decide in the State representation to show results2 only if results1 is there.
The only time I would orchestrate APIs is when there are dependencies between the calls, but it might be simpler to do this orchestration in the backend if possible. It's even perfectly ok to present intermediate results when it makes sense. The "state" of the action is not relevant to the application state, the action can just informs the model (application state) of its progress.
Slađan Ristić
@sladiri
Jul 22 2017 13:36
Thank you. By "blocking", I meant cancellation, just to be more clear. I was not sure about the ordering for example, I thought that hiding Result1 without Result2 must be in the model. I guess I have to keep the state-representation aspect more inside my head. :)
Jean-Jacques Dubray
@jdubray
Jul 22 2017 17:24
yes, I feel the factoring of the pattern is just right. As you can see every programming model is a deliberate choice (ancillary state machines,...) and we should not make that choice in a dogmatic way, FP says XYZ so that's how we have to do it. That article was pragmatic about API calls in Redux: Redux-First Router data-fetching: solving the 80% use case for async Middleware
The way we factor code should be deliberate, not just because this guy said so (that includes me) or because everyone else does it that way. For me there is clear evidence that a better factoring involves: proposals, isolated mutations and view decoupled from state representation.
Antanas A.
@antanas-arvasevicius
Jul 22 2017 18:58
Hello
I've read a new article on SAM and it was easy to follow
Antanas A.
@antanas-arvasevicius
Jul 22 2017 19:06
for me it's not clear if state function computes application control state {error, done, computing}, and transition predicate decides (3) where to go next
but what what if multiple transitions could be computed? How this situation is handled?
Some kind of non deterministic FSM?
Antanas A.
@antanas-arvasevicius
Jul 22 2017 19:12
And how about situation when multiple SAM domains with different states works interleaved with each other, is composition possible at all?
Antanas A.
@antanas-arvasevicius
Jul 22 2017 19:21
Also model's "accept" function contains all actions which can be made on model, why it's better than just have a method on model? e.g. model.incrementBy() ?
and model calls state.render(this) after accept, it looks like it is a MVVM, but Model of MVVM is Action instead
Slađan Ristić
@sladiri
Jul 22 2017 20:43

@antanas-arvasevicius

why it's better than just have a method on model? e.g. model.incrementBy() ...

If you do not do this, you have less coupling between actions and model. Actions can then be reusable across models. Increment by is a "harder" case, where you have to give a "hint" to the model, that a value should be incremented. There is no way to avoid that, I guess.
So an increment value could then be used on different models. Each model could do its mutations differently, interpret the proposed value differently.

Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:01
@antanas-arvasevicius it would violate the step principle (Action->Model->State), assuming you are in a synchronous case, triggering a second action would result executing this action from step N-1, it's not recommended, it's always best to execute a step. You can of course do it, but at your own risk. It's reasonably safe for an action to present two proposals, it's not a great idea to fire two actions (~action composition). In theory, actions do not compose, it is only their implementation which can be composed functionally.
Different SAM domains is well covered as:
  • either simple unsolicited notifications (State function notifies a SAM instance/domain of a new state representation as an action on the model of that instance)
  • or a request/response in an action of the parent domain
Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:09
SAM supports a many-to-many relationship between actions and acceptors, I believe that's very important (better decoupling), but that's just a preference, it does not change the proposal/mutation semantics.
Antanas A.
@antanas-arvasevicius
Jul 22 2017 21:10
but in either case there is a coupling between action and model (you need to know what model accepts before writing action)
Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:11
I believe data binding is wrong, the role of the State function is to compute the properties of the view components, such that the model does not have to understand how its properties are rendered
Antanas A.
@antanas-arvasevicius
Jul 22 2017 21:12
so state function becomes ViewModel
Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:12
yes, there is a coupling of course, but its more decoupled if you support a many-to-many relationship (many actions can trigger an acceptor -that's easy, and many acceptors can be triggered by a single action, without the action knowing which one is triggered, that's a bit harder)
Yes, if you want to see it that way that's ok
Antanas A.
@antanas-arvasevicius
Jul 22 2017 21:13
I'm just trying to mindmap a bit with a known definitions
Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:13
the state function can notify everyone interested in the representation (including variants of the representation) when a new state representation is available
sure, no problem
Antanas A.
@antanas-arvasevicius
Jul 22 2017 21:15
I still have feelings somewhat is it necessary to do that way for everything
and what about if I need a new action, I need to write new action and augment my model (by appending code to "accept" function)
and also composability of two SAM's
Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:18
It depends, but right now I have to refactor a big piece of code because I put a bunch of code in the view when it should have been in the State function. I could have factored the view better, but SAM's roles are very clear, it avoids that kind of mistakes.
I rarely need a child instance
All I can tell you is that the code I write has very few bugs
Without SAM, I would have produced spaghetti instead. Maybe it's just me.
Antanas A.
@antanas-arvasevicius
Jul 22 2017 21:20
Maybe practice ;)
and experience
I doubt is it good to do everything in advance in that style
Jean-Jacques Dubray
@jdubray
Jul 22 2017 21:25
I have the opposite opinion, I get burned each time I don't apply it with precision, but I am biased, or it's just the way I think.
Nivani
@Nivani
Jul 22 2017 22:50
@antanas-arvasevicius, maybe I am wrong about you seeing it this way, but you do not need to have one accept function that does all mutations on your model. To split up the code you can call multiple acceptor functions from the accept function that only make changes to the model for the types of proposals that they are responsible for.
Jean-Jacques Dubray
@jdubray
Jul 22 2017 23:18
this is what we do, I have a component model that splits actions, acceptors and reactors (state function)