These are chat archives for jdubray/sam

24th
Feb 2016
Michael Terry
@formido
Feb 24 2016 00:06
Don't you increment the value in the action and then present it to the model?
Gunar C. Gessner
@gunar
Feb 24 2016 00:12
Oh, now I get it. Presenting the new value to the model makes more sense to me (even in a SAM perspective) (e.g. present({ value: value+1 })). But this doesn't work well for concurrency. I guess both methods are valid.
Gunar C. Gessner
@gunar
Feb 24 2016 00:42
@formido not really, he's actually sending a "decrement" action but attaches the current value: actions.decrement({counter: model.counter},model.present) ;
Michael Terry
@formido
Feb 24 2016 00:47
Cool, that's what I was seeing too
Jean-Jacques Dubray
@jdubray
Feb 24 2016 01:39
so, inc/dec add/remove are more CRUD like operations, therefore should be handled by the model rather than the action. The action should present {incrementBy: 1}
However, I wanted to illustrate that in general actions present potential values to the model, not operations on the model
hence model.present({counter: model.counter+1})
for a "change of address action it should be:
model.present({street: '123 main st', city: 'Seattle', zip: '98101', state: 'WA'})
Michael Terry
@formido
Feb 24 2016 03:29
Alright, so you're saying in a non-didactic implementation, that increment operation in the rocket launcher example would be handled in the model?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 03:34
yes, it is preferable to handle add/remove and inc/dec in the model.
Gunar C. Gessner
@gunar
Feb 24 2016 11:12
I just realized that present() in SAM works like the next-state-relation in a state-machine, right?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:20
No sure I understand? This is really aligned with TLA+ / Paxos protocol:
  • proposers -> actions
  • acceptors -> model
  • learners -> state
From there, the way "state machines" really work is not as the classical definition, (S1,A,S2) but rather S2 is derived from the model A has no idea if it will end up in S2 or not (at run time)
so semantically nap and present are very different. present mutate the model, nap triggers an action. No sure why they would "work the same way". It's a reactive loop
Gunar C. Gessner
@gunar
Feb 24 2016 11:31
Well, the present function receives a dataset and if it matches one of his relations (if, then...) is accepts the value (mutates the state). So it kinda looks like a set of allowed relations hence next-state-relation
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:33
Yes, but present does not initiate any actions (other than the CRUD to the storage) which incidentally could mutate the state too.
I don't view them as the same at all.
Gunar C. Gessner
@gunar
Feb 24 2016 11:36
not the same, just analogous. writing all this if and elses made me recall the "state-machines" paper and the next-state-relation.
Gunar C. Gessner
@gunar
Feb 24 2016 11:41
I often find myself writing dense presentfunctions - that check for too many state variables - and I see your example is quite lean. Do you have a tip on how to model this?
nevermind. I see where I went wrong.
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:44
You have to understand how a state is defined. If-then-else is not (always) the best way to do that. The true definition of a state is a range of values. For instance the car is in the started state rpm in ]0,600]
so you can write is as if (rpm>0) { started = true ; }
or you can write it as started = (rpm>0) ;
I like the later, it is the "true" definition of a state
Gunar C. Gessner
@gunar
Feb 24 2016 11:45
or function started(rpm) { return rpm > 0 }
yes that makes sense
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:46
But I don't want to be prescriptive because it is not always the best way to write it, sometimes it's quite heavy
Gunar C. Gessner
@gunar
Feb 24 2016 11:47
Using Redux with SAM generates more boilerplate b/c I can't write model.started = data.started || false ;, I have to dispatch an action to do this, so it actually becomes 3 LOC instead of 1
      if (dataset.started) {
        dispatch({type: 'START' })
      }
an a minimum of 2 LOC more in the reducer
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:49
Yes, I think Dan is going to have to make the actions functional
Gunar C. Gessner
@gunar
Feb 24 2016 11:52

Dan on /sam-architecture

If actions are functions operating on the state you no longer have a "history" of the changes that you could serialize or replay.

Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:53
it's not exactly true, you have a history at the present() level
It works the same way
Gunar C. Gessner
@gunar
Feb 24 2016 11:54
you mean by making your store Immutable? (i.e. having a log of the Store)
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:55
You have similar control points between present() and state()
just like action() and the output of the reducer() in the case of Redux
Store -> State
Reducer -> Model + Action
With time travel, it's not important how you got somewhere, that's the beautify of State Machines they have no memory
You can return at any state, then you know the actions that can be taken
Time Travel in SAM would work at the State() level, you'd plug in an old model snapshot and you are ready to go, you can calculate nap() and the state representation
Gunar C. Gessner
@gunar
Feb 24 2016 11:58
In Redux you may live-modify an reducer and the history gets reevaluated. Do you think that's possible too?
Well it should be, right?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 11:59
but... Redux is severely limited since the reducer cannot have time-based dependencies
if you impose that constraint on SAM that works too
it's a bit fake if you ask me. It is not as important as being able to change the code at a point and change the next step
It's not real-world enough to limit actions to be pure functions with no time dependencies
Gunar C. Gessner
@gunar
Feb 24 2016 12:01
That's why all the workarounds (thunks, sagas....)
Jean-Jacques Dubray
@jdubray
Feb 24 2016 12:02
... exactly, that is wrong
I'd say, if you know your code conforms to that constrains then you get that nice benefit, but it's wrong to force your code to be that way to get that benefit, makes no sense
Gunar C. Gessner
@gunar
Feb 24 2016 12:37
Would it make sense only to run nap() if the model actually mutated? If nap() should be pure, then it'd be like some kind of memoization.
brucou
@brucou
Feb 24 2016 14:22
As was mentioned, a necessary step is to have actual code samples, for example porting redux examples (https://github.com/reactjs/redux/tree/master/examples) so the two can be compared. Otherwise this remains the usual unsubstantiated claiming and confusing explanations and trust me because I name some maths/whatever which are actually not relevant to the matter at hand. It is very simple, if it is so great and so productive (50% productivity gains has been claimed, whatever that means), it should be easy to show. Time is passing by, noise is being made for publicity purposes, but no code of interest is showing.
Another example is the cyclejs challenge examples
This would allow direct comparison and precise discussion.
Here is the cyclejs challenge, there are already quite a few sample from other patterns : https://github.com/staltz/flux-challenge
Jean-Jacques Dubray
@jdubray
Feb 24 2016 16:20
We have actually provided code for most of the examples here https://github.com/reactjs/redux/tree/master/examples
For the shopping cart, as mentioned before, I work with a client on that project so I cannot share the code readily, but I can answer any question you have.
I am actually you are not asking Redux to show how they would implement the rocket example... since to Dan's admission Redux doesn't do async and you'd have to bring Thunks into the picture. It would be fair don't you think?
Working on the challenge
Gunar C. Gessner
@gunar
Feb 24 2016 16:32
@jdubray you're working on the flux challange?
Michael Terry
@formido
Feb 24 2016 16:57
Aha! Flux challenge...exactly what I've had on my mind this morning as a great trial for SAM. I was going to tackle it this weekend.
Michael Terry
@formido
Feb 24 2016 17:16
@brucou If you can't get the principle from the Rocket Launcher example, I don't see how more of the kind is going to help
If the philosophy isn't convincing, toy examples aren't the answer
Does anyone go to TodoMVC to compare examples when picking a framework?
You have to believe the reasoning makes a difference in a real application and then try it
The toy examples are already here
brusand
@brusand
Feb 24 2016 17:28
I am going to try sam on a simple réal use case a portal with a welcome page (undefined user) . on this page a login form and when the user is authenticated, a home page is display bases on thé rôle of thé user... I ll try to code it un JavaScript and after try to add type script ans for d'un angular 1
For fun
Michael Terry
@formido
Feb 24 2016 17:31
Nice
Michael Terry
@formido
Feb 24 2016 19:37
@jdubray Could you convert a Django MVC app to SAM? I don't quite see how.
Once the Django "view" sends its response to the client, running a nap() callback doesn't seem to make a lot of sense since it can't affect what's going on in the browser until the browser makes another request
Jean-Jacques Dubray
@jdubray
Feb 24 2016 19:48
As long as you can implement V = f(M) then you should be ok, it's a bit harder if the view is statically defined as templates. But still... my expectation is that you can. Let me explain
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:01

... ends its response to the client, running a nap() callback doesn't seem to make a lot of sense since it can't affect what's going on in the browser until the browser makes another request

yes and no, it might still be important to update the model for the next request. You may also trigger actions with no side effects.

what's key to understand is the nap() actions cannot change the view. They have to go through an iteration action -> mode -> state (new state representation, nap())

In general in Web applications you don't have too many server side next-actions. They will most likely be running in the browser

The whole pattern can fit in the controller of an MVC framework. The key is simply to follow the semantics, there is nothing that says you cannot use MVC framework. I don't need them, I use node.js+HTML5+CSS3, I never feel I need anything else. But if you have some legacy, then there is not much choice.
Michael Terry
@formido
Feb 24 2016 20:03
Legacy, yep
Yes, I had considered that nap() actions aren't nearly as likely on the server
So breaking up the pattern across the client/server divide is OK, you think? Next Actions triggered on client but model on server?
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:06
Yes absolutely!! That's the absolute beauty of SAM is that it makes no assumptions on the wiring
Michael Terry
@formido
Feb 24 2016 20:06
Excellent
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:06
SAM will also fit within an HTTP Req/Resp
Michael Terry
@formido
Feb 24 2016 20:06
I have a feature due at work that I will try to pattern this way
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:07
I do that with Node.js all the time. I enter the request with an API call and (I know it's heresy) the response returns an HTML state representation
but the response could also return the model
Michael Terry
@formido
Feb 24 2016 20:07
awesome
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:07
Let me know if you have any question, happy to assist.
Michael Terry
@formido
Feb 24 2016 20:08
:+1:
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:08
SAM is just a factoring of the code, it's not a library. The premise is that factoring will help you write your code faster (~50%), with less bugs (because the business logic is clearly separated in Actions, Model, State) and it will be much more maintainable (new actions, new model elements, new states / next actions...)
Michael Terry
@formido
Feb 24 2016 20:11
So far I'm buying, because the division of responsibilities makes sense to me and you've discussed a lot of issues I've tangled with in actual battles with my code. But the truth can only be known when the rubber meets the road
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:11
That's why originally I wanted to talk to Dan because Redux is so close, yet, its semantics are not precise enough, you start writing some spaghetti code (Action+Model are coupled and its lacking the discipline Action -> Model -> State, nearly all thunk examples show multiple actions where it should be thunk(action) -> reducer -> store -> thunk(action)
I agree! again happy to answer any question.
thank you!
the SAM factoring is also easy to adopt, it's not really bending your code in any way, almost the opposite. Last but not least since nearly everything (except for the Model) is a pure function, then your code becomes much more testable. Try to test MVC...
Michael Terry
@formido
Feb 24 2016 20:15
I've been living with MVC my whole programming life, and I've always hated it
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:15
Yes, I think a lot of people have... I started to use MVC 25 years ago.
Michael Terry
@formido
Feb 24 2016 20:16
To me, MVC is just a description of what GUI app code looks like if you do the most naive thing possible
But I couldn't think of anything better so
Jean-Jacques Dubray
@jdubray
Feb 24 2016 20:45
Me too.. it's only when I stumbled on TLA+ and React that things started to change, and it still took me a good 6 months to put everything together.