These are chat archives for jdubray/sam

13th
Apr 2016
I really like the idea behind this library: Union Type
https://www.npmjs.com/package/union-type-js
An example of a simple React app using Union Type:
https://github.com/winitzki/flyd-react-sample/blob/master/app/model.js
devin ivy
@devinivy
Apr 13 2016 01:15
cool stuff!
devin ivy
@devinivy
Apr 13 2016 02:19
that was a great watch :thumbsup:
Jean-Jacques Dubray
@jdubray
Apr 13 2016 02:28
yes I found that too, very concise explanation on how all these frameworks are wired.
Of course the next question is why you would want to do that at all.
devin ivy
@devinivy
Apr 13 2016 02:32
the main reason i heard the speaker advocating is that the way his program might fail is easy to reason about.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:02
Yes, I heard that too ("you no longer about the order in which things happen, the reactive loops will always be executed in the right order")
But you pay a very heavy price for that very tiny convenience. SAM gives achieve pretty much the same result because it implements a reactive loop as well, but without Stream hell.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:10
you realize that these architecture suffer from 3 major issues:
  • Persistence is an afterthought, the article proposes a particularly bad articulation (the facade handles persistence, really?)
  • because the reducer couples actions (proposers) and mutation (acceptors) you cannot easily filter the actions based on the current state of the system (the model subscribes to all possible events, then has to make sense of them)
  • mutating 100% of the model does not scale in real-world applications
devin ivy
@devinivy
Apr 13 2016 03:15
i see what you're saying, but i have some trouble with that last point. typically the model and the state presented to the view are conflated in the redux pattern, unlike in SAM. while you can't replace the entire model, it may be fine to replace the state that is available to the views.
point being, i guess, is that it's hard to say that mutating 100% of the model doesn't scale, when redux isn't replacing what SAM would call the "model".
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:16
The "real-world" of Redux actually requires Sagas and Thunks (action as a function, not intent)
Sagas break the principle #1 of Redux (and Reactive programming) -> single state tree
SAM and Redux+Sagas+Thunks are overall equivalent, albeit with a different internal factoring
SAM supports a single state tree
Sagas are 100% stateful and their state is inaccessible to the Reducer.
devin ivy
@devinivy
Apr 13 2016 03:21
have you looked at how reflux does some of this?
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:21
Forcing the semantics of a "Reducer" on the Front-End architecture is simply the wrong things to do, it only brings problems, for zero value
No I didn't
devin ivy
@devinivy
Apr 13 2016 03:22
reflux allows you to create sort of "sub actions" to a main action.
the standard ones would be "failed" and "completed"
but you can define any that you'd like.
reflux also gives an explicit hook for each action to determine if it should really be emitted or not.
not entirely dissimilar to sagas and thunks
or at least, those features are used for similar reasons as sagas and thunks.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:29
The general problem is that React's architecture requires that the changes to the application state be applied entirely at once otherwise the view could render multiple times, dependending how you wired your application.
That's a constraint that's not very realistic.
When you are building a web app you need to consider programming model, wiring and architecture.
Facebook must implement as many CPU cycle on the client as they can, when you have 1.5 B users that is vital for you.
I am not sure that architecture suits everyone.
devin ivy
@devinivy
Apr 13 2016 03:32
i actually use reflux with polymerjs, and i don't change the whole state at once. see https://github.com/devinivy/polymer-funky-flux
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:32
The flow to mutate state is: propose, accept, learn. There are certainly many ways you can achieve that flow and Redux is learning it the hard way. Perhaps instead of sputtering a bunch of libraries and patches they could study what is needed and then come up with a unified approach.
I'll take a look, I have trouble to see how the actions connects to the store. It looks like Reflux supports the separation Proposer / Acceptor.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 03:52
I would say reflux and SAM are relatively well aligned based on this code sample:
https://github.com/devinivy/polymer-funky-flux/blob/master/stores/cart-store.html
I generally prefer a more generic "present" method for the model, I tend to see actions as being something very application specific while the model is the first "enterprise class" asset, i.e. the same model should work across (several) applications
but that's really a preference, as long as it is a reactive/unidirectional flow and the actions proposes values to accept, then we are aligned.
iwangheng
@iwangheng
Apr 13 2016 07:01
where can i find a example that use react + Redux+Sagas+Thunks
Jean-Jacques Dubray
@jdubray
Apr 13 2016 09:54
? not with SAM, Sagas are an anti-pattern. They break the single state tree principle.
Fred Daoud
@foxdonut
Apr 13 2016 14:05
@jdubray : Good day! One aspect that seems to distinguish SAM is the idea of "propose / accept". Do you have a working code example that demonstrates this separation, and more importantly, showing a scenario/use case where an action proposes a change to the model, but the model rejects it? I'd like to gain more understanding of this aspect, and a use case in a code example would be most useful.
Gunar Gessner
@gunar
Apr 13 2016 14:43
@foxdonut a very simple example is the countdown laucher. if user presents { launched: true } before countdown === 0 the model will reject it.
Fred Daoud
@foxdonut
Apr 13 2016 14:54
@gunar I see, thanks. How is that different than having a reduce, function(state, action) where action is launch and the function sees in state that it is before countdown === 0 and so refuses to update the model?
Gunar Gessner
@gunar
Apr 13 2016 15:03
@foxdonut in this case, seems very similar indeed.
devin ivy
@devinivy
Apr 13 2016 15:05
is it possible that the difference is that the proposal contains the particular state change? whereas an action itself doesn't propose a particular state change.
Gunar Gessner
@gunar
Apr 13 2016 15:06
and by that you can have your business logic in the model instead of in the action
devin ivy
@devinivy
Apr 13 2016 15:07
i will have to look at some more SAM examples :)
Gunar Gessner
@gunar
Apr 13 2016 15:07
otherwise the action would need to have the entire knowledge of the system, what is supposedly a very bad coupling. but I have to think about it.
Fred Daoud
@foxdonut
Apr 13 2016 15:33
@gunar why would the action need to have the entire knowledge of the system? the action just asks to "launch", nothing else.
devin ivy
@devinivy
Apr 13 2016 15:35
in SAM, it appears that the "action" proposes specific changes to the model: https://github.com/jdubray/sam-samples/blob/master/todomvc-app/js/app.js#L367-L373
then the model decides how to deal with the proposed changes: https://github.com/jdubray/sam-samples/blob/master/todomvc-app/js/app.js#L228-L240
that's my understanding, at least
if i'm understanding correctly, the action does have to have knowledge of, for example, the shape of the model.
i take that back, partially. in this case, the proposal to the model (to delete an item) is processed: https://github.com/jdubray/sam-samples/blob/master/todomvc-app/js/app.js#L167-L184
Fred Daoud
@foxdonut
Apr 13 2016 15:51
@devinivy thank you, that clarifies some things. it looks like there is a single present function to propose changes to the model. then the model has a ton of if statements to figure out what needs to change. That doesn't look like it would scale very well. Just for this small todo example, the CRUD function is a mess.
devin ivy
@devinivy
Apr 13 2016 15:54
it does confuse me a bit too. it seems like the model is being presented with free-form data. my initial reaction is that it's much nicer for the model to subscribe to actions, and know which action it's dealing with in order to at least understand the format of the data it's being presented with.
when the delete action is called in the example above, and that ends-up as a presentation of { deletedItemId: x } to the model, it seems like some information has been lost. that actions aren't really being taken advantage of. the model now needs to understand "here's something called deletedItemId" rather than "here's an action expressing that it would like to delete an item."
of course the model could still reject that action if it wants to.
Gunar Gessner
@gunar
Apr 13 2016 16:31
Actually SAM is about the architecture. You may implement the Model however you'd like.
@foxdonut the action need to have knowledge of the entire system in the sense of the action has to know the state/model. that's the main concern with, there's this tight coupling between actions and model.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 16:53
Great discussion!
Let's take a simple example to clarify. Consider a "Change of Address" Action
Users enter their address in a form and submit an "intent" to change their address to the proposed value.
Typically these days, the application will call a "getPostalAddress" API to convert the user input into a set of values that will form the basis of the proposal to mutate the model
Now, the company only do business in specific countries, so the model has rules that the action do not need to know. If you try to mutate to an address from another country, the model should mutate to an error, not the proposed values.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 17:00
Conversely, if your company was only doing business in one country, and is now expanding to others, an existing action could be updated (without changes to the UI if that makes sense, eg when your products are country specific) to provide a default value to the proposed country since now the model requires an address to provide a country value.
When you write counter++ ; you are in essence proposing to mutate the state of the counter to a new proposed value.
var p = counter + 1 ; counter.present(p)
This message was deleted
this is the flow of mutation, you cannot tamper with it, you can optimize it when you know what you are doing, but the operation of mutation integrate constraints that are simply unknown to the proposer
in the counter example, there could a constraint that the value of the counter cannot be greater than 10
it would not make sense for the proposer to know that constraint, or conversely in the context of the proposer the value cannot be greater than 10 but the model has no constraint.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 17:05
These situations need a clear factoring of the logic, something that the concept of a reducer does not provide. This factoring offers a healthy evolutionary path to the system
And I am not even talking about S() and nap()
The action should never be in the position to know of the entire model. An action's job is to translate (user) intents into proposals to mutate the application state, nothing less, nothing more.
This provides a very healthy decoupling between the user intent and the structure of the model.
Jean-Jacques Dubray
@jdubray
Apr 13 2016 17:13
SAM supports naturally the concept of action "hang back" where the user can request multiple actions and the first one that presents value to the model wins (this is a scenario that Netflix had difficulty implementing with existing frameworks)
Here is the netflix presentation where they explain the need for "hang back" https://www.youtube.com/watch?v=5sETJs2_jwo
devin ivy
@devinivy
Apr 13 2016 17:54
@jdubray are an action calling model.present() and a model subscribing to an action both potentially consistent with SAM?
because i think i normally factor things very differently. normally i call an action "the thing that the model/stores receives", whether it's by a proposal()(-call->) or a subscription (<-listen-). i don't have a name for the handler that translates user interaction into what i would call an action. perhaps an action-creator.
ultimately it's nice for the model to deal with an action, because they're implicitly union-types, whether or not there's a library being used to enforce those types.