These are chat archives for jdubray/sam

29th
May 2016
Jean-Jacques Dubray
@jdubray
May 29 2016 02:47
@antitoxic I added a React/Spinner example to SAM samples: https://github.com/jdubray/sam-samples/blob/master/react-spinner/index.html
The action, whether successful or not should flow the spinner id such that the State function can clean it up
There is no need to "loop" into the model
Jean-Jacques Dubray
@jdubray
May 29 2016 03:11
Incidentally React makes it rather trivial to create child SAM instances
Anton Stoychev
@antitoxic
May 29 2016 07:21

@509dave16 I will have a look

I see the same similarities. There are however some differences, SAM's State function (which main goal is to create the "State Representation" just like Containers).... [if] there will be multiple control states which is not SAM's intent for the State function. There is generally one control state.

Does SAM pattern requires a single state-control function that decides everything that is to be rendered?

Yes, some systems may be in a "composite state" or there could be logically separated control states, but in general there is only one.

I understand that. Though, this doesn't give me an insight to the following cocmmon scenario: if I have a nested DOM (using JSX) and the inner-most element is the <CounterIndicator> which after some model mutation needs to change it's success property to true, do I have to figure out the <CounterIndicator> property value in the one-and-only top-level State function? This doesn't seem right to me. It's mashing all logic for all components in 1 big fucntion. And I have to pass the success property through all ascending elements down to my inner-most <CounterIndicator. 1) Is this what SAM suggests - to pass all the data, for all components through the root component? That means I need to either have 100 properties (like <Root indicatorOneSuccess=true indicator2Success=false...) on the root component that trickle down to the inner-most components or have 1 very ambigius property called model='' which contains all that and which breaks the concept of components that are only aware of the properties they need to render.

I don't see how my indicator turning into success is a property of the system. I could have 10 indicators on a single screen. Each depending on the context they are in. One can indicate an error in a form which the user is trying to submit, another could indicate error in another form or successful data submission. These are context-based. I don't like to think that form_1_username_field_success or form_2_password_2_success is a state of my system. These are form-specific-states/component-specific. My system only cares whether the form is submitted or not, and I think the details and individual states of the sub-systems would be overwhelming if included in my one-and-only top-level State function (think field-specific errors, animations states of every components, field-specific toggles or values...)

For instance a complex form (or wizard) would certainly mandate it's own child SAM instance, it is only when you are ready to submit the form that you would then invoke the action on the parent instance.

This seem to support the idea of sub-systems. But then 2) do I have a single state tree or do I have several state trees?

..[about the spinner]..That's a bit of a "bend" in terms a single state tree. Since obviously you have some application state that is unknown to the model. The view would call the action passing the div responsible for the spinner (assuming you use a CSS spinner). Upon completion of the action, then the spinner-id would be presented to the model, say to a "turnOffSpinner" property value. The State function would then remove the corresponding div from the view.

Ah... My model will know about the spinner? Also how would it convey to the state that it needs the spinner turned off? Do you mean putting a flag turnOffSpinner: true in the model itself? I'm trying to see the goodnes of this but I'm really having trouble.

State function is responsible for invoking the next-action-predicate (nap) and optionally, but highly recommended, for computing the allowed actions in a given control state..... key problem of the Redux architecture is that it has no way to keep track of what is supposed to happen at any given time.

More and more, I'm thinking that the one-and-only top-level State function is an all-seeing eye. I'm confused here. The only thing that would solve that is sub-systems but then I'm confused with single-state-tree and sub-systems (sub-SAMs)

The simplest implementation would be to have a single container so every model mutation will provide a fresh set of props to trigger the entire rendering. nap() and allowed actions could be computed in componentDidUpdate

I don't understand that single container to every model mutation. What do you mean by container in this case? And if we are talking about React/JSX world, then do you mean fresh set of properties for the root component or fresh set of properties to every component in the DOM tree.

...basic Spinner example on github

That's a broken example for several reasons:

  1. You don't have access to parent ascending elements in JSX and you can't have IDs in JSX because that component can exist on several places. That's why it's a reusable component. So you can't query it by document.get... or other selectors. I understand that the example could be simplifying things but I think this is a key problem here - this is a fictional example, not a real-world one. If you have many spinner components you only have one choice for targeting a particular one and start spinning it - you have to do an action that triggers a change in the model and then on the next rendering you have to derive from the change that this specific spinner should start.
  2. That's not the common case of spinner or animation. Usually the spinner or is an actually DOM element (like SVG) that should be shown or hidden depending on model/state-tree. In react I would do that with JSX conditionals - if props.loading then render SVG, if not don't render SVG. Again this requires a roundtrip to the model and rendering in order to have this loading property set to true.

Overall... - if you introduce a new method stash() and several subsystems, then where would their data go in the single tree? To me, having sub-systems is just like having Redux container components. If having subsystems is ok, what's the problem with Redux containers? The nap? I'm having hard time picturing the benefits.

Jean-Jacques Dubray
@jdubray
May 29 2016 08:05
@antitoxic here is a parent/child example: https://github.com/jdubray/sam-samples/tree/master/react-child-instance (form validation)

if I have a nested DOM (using JSX) and the inner-most element is the <CounterIndicator> which after some model mutation needs to change it's success property to true, do I have to figure out the <CounterIndicator> property value in the one-and-only top-level State function?

The State function does not know how view component render, it just decides which view component renders and passes fragments of the model to these components. The key here is to keep the view components and the model decoupled.

Here I would have the <CounterIndicator> component to decide whether it should display true or false based on a "threshold", however the threshold value should come from the State so that the component is generic (unless of course that value would be common to all components, say like a freezing temperature).
Jean-Jacques Dubray
@jdubray
May 29 2016 08:12

Is this what SAM suggests - to pass all the data, for all components through the root component?

that's inherent to single state tree architectures. You can certainly break it down a bit, but you can't have a single state tree, with stateless components and start somewhere in between.

The traditional stateful component component looks a lot more confusing to me.

I don't see how my indicator turning into success is a property of the system.

so again, it is not. They key to a successful SAM implementation is to have the view 100 % decoupled from the model, so the model does not know how the view processes it's values and the view components do not know how the model is structured (not do they require the model to be structured in the way they want to represent information).

These are form-specific-states/component-specific. My system only cares whether the form is submitted or not, and I think the details and individual states of the sub-systems would be overwhelming if included in my one-and-only top-level State function (think field-specific errors, animations states of every components, field-specific toggles or values...)

yes, we agree, please see the parent/child example I provided

do I have a single state tree or do I have several state trees?
you have a state tree per SAM instance
Jean-Jacques Dubray
@jdubray
May 29 2016 08:21

My model will know about the spinner?
well, that's part of the application state, something is spinning. The view must be stateless, so there is not much choice left.

Also how would it convey to the state that it needs the spinner turned off? Do you mean putting a flag turnOffSpinner: true in the model itself?

The sample code just passes the identity, again this is part of the application state. What the sample code shows is that you do not need to "loop" back through the model to run the query. You can run the long running query in the action and only when it is done (success or error) the spinner identity is passed through.

If you need this action to be cancellable then you'll have to "stash" the spinner identity at the beginning of the action such that a cancel action would turn off the spinner properly.

nap() is for automatic actions, if you have an application that has the need for it, you'll see the benefits
I am not familiar enough with React to evaluate your question further, not sure if someone on the list can help.
@509dave16 Could you help answer @antitoxic questions ?
Anton Stoychev
@antitoxic
May 29 2016 10:46

@jdubray alright.

The State function does not know how view component render, it just decides which view component renders and passes fragments of the model to these components. The key here is to keep the view components and the model decoupled.

I understand the idea that state function doesn't know about how the view renders, just which view to render. In that sense view is a renderable component. Having the example of deeply nested elements, the strucutre implies there will be a sub-system because a view's deep component tree can have all sort of combinations of descendants been shown/hidden/colored/sized and the State function (i'm guessing here) wouldn't have 100 views to render for all scenarios. So subsystems is the way to go. This is a good clarification. I suggest this is included early in the docs, because I'm guessing much of the readers are getting stuck in this logical situation.

If you need this action to be cancellable then you'll have to "stash" the spinner identity at the beginning of the action such that a cancel action would turn off the spinner properly.

Is the stash going to be part of the tree?

nap() is for automatic actions, if you have an application that has the need for it, you'll see the benefits

I understand what nap() is for. I'm just trying to visualise a real example of it, a bit more complex than decrementing/incrementing. I'm strunggling. Please excuse this. I'm not trying to throw the idea away, I'm just trying to figure out an example that is comprehansable for me. Besides lack of automatic actions, the other argumentation against Redux is that you never know what action follows but I'm seeing that parent-child relations will be used a lot with SAM, and in the end much the actions will be obsucred in sub-sub-sub-systems.

@509dave16 I will be grateful for any insights for react and redux combo with cases like the spinner example from Jean-Jacuqes above. In React there is no modification of the view without rerender (i.e. can't add a class or query by id)

not sure if someone on the list can help.

I will be grateful for any redirection as well.

In the end, I think I will mix best (for me personally) of both worlds - SAM and React+Redux. I like SAM's direct way of passing actions, not Redux's dispatch() of actions, I like the idea that the model is responsible for data integrity validation, I like the state function mapping model to view rendering. I don't understand why is the rage against Redux and React development, even graphql (forget about Relay). From what we discussed and what I've read about SAM, I always used very similar aproach when thinking in React and Redux - i had wrapper React components (in SAM's world this is a sybsystem) which mapped passed data from the statetree (in SAM - it's the model) to children component (SAM's views) and render() function of the wrapper component (SAM's subsustem state function) decided which children to be shown via JSX conditionals. For me it's just terminology difference. If the message in the initial article was that SAM is just few little things different than React, it would have been much easier to comprehend. I also don't like the attitude towards React develpers ("the kids in Facebook didn't think about this or that"). I like SAM, because I always thought in this way. I also like storing all data in 1 single tree, so it's easy to persist (localStorage for example) so I'm still thinking how to mix "best of bost worlds" so that it fits me.

Jean-Jacques Dubray
@jdubray
May 29 2016 11:28
yes, the idea behind stash is that you present value to the model without rendering, such that whichever action present its values to the model (with results or cancellation), we have the correct application state (spinner is running).

In React there is no modification of the view without rerender (i.e. can't add a class or query by id)

This is not correct, in the example I do select a DOM element by id and modify it outside of React rendering loop.

Anton Stoychev
@antitoxic
May 29 2016 11:33
Everything is possible but it's not recommended so nobody does this (unless the logic is in componentDidMount()) Next rendering loop will dismiss the changes + querying by id (or other selector) while still possible, is highly unrecommended unless you only have a component once in an app.
Jean-Jacques Dubray
@jdubray
May 29 2016 11:33

I don't understand why is the rage against Redux and React development, even graphql (forget about Relay)

the question is really why do you need React, Redux GraphQL or Relay at all? I can't really find an answer to that question. I do like JSX for sure, but it comes with so much baggage. Look at Redux, this is non-exhaustive list of add-ons:

  • redux-sagas,
  • redux-gen,
  • redux-loop,
  • redux-effects,
  • redux-side-effects,
  • redux-thunks,
  • rx-redux,
  • redux-rx
Anton Stoychev
@antitoxic
May 29 2016 11:34
These are all optional.
And none of these bring much to the table.
redux in its core is just the concept of single state-tree per app. That's all
Jean-Jacques Dubray
@jdubray
May 29 2016 11:36
But even that they can't follow themselves, Sagas break that principle
Anton Stoychev
@antitoxic
May 29 2016 11:36
Yep. But that doesn't mean all people in the world suddenly started using sagas.
Jean-Jacques Dubray
@jdubray
May 29 2016 11:37
In the end, they focus on the wrong problem. The problem is mutating application state, not making parts of your application "testable". They actually try to ignore what mutation is altogether.
I agree that through common sense, you'd focus on doing the right thing to mutate application state, the question is really, why not apply the proper formalism to mutate application state?
why reinvent the (wrong) wheel?
Jean-Jacques Dubray
@jdubray
May 29 2016 11:43
Look at how hard it is to support long running actions in Redux? Sagas can be made irrelevant with nap() while following the single state tree principle. When you talk the Redux guys, they don't want to talk about these questions. Not sure who hates who. But you can bring any questions to this list, I am not going to hate you, whether I have an answer or not for it. In software, there is no formalism that is perfect. What are the Redux guys thinking?
Anton Stoychev
@antitoxic
May 29 2016 11:44
In order to evaluate what is "proper" people need an understandable intro and good tooling. Neither the article, nor the website about SAM gives me that. It gives me a exhaustingly long read. Or in other words "the article and website focus on the wrong problem. The problem is 'tell me how to do what I do better'" Then I will evaluate what is 'proper' for me.
Jean-Jacques Dubray
@jdubray
May 29 2016 11:44
And we are not even talking about immutability, do you really think that having to duplicate the entire application state for every action is really reasonable?
Anton Stoychev
@antitoxic
May 29 2016 11:45
I could be an odd case but really, I needed to stop and have a break 3 times before I finish the topics of SAM and I still need to come here in this group and ask questions.
Jean-Jacques Dubray
@jdubray
May 29 2016 11:46
Sure, I accept the critic, happy to improve as people ask questions. I am not paid to do this, I don't have a marketing organization behind me.
Anton Stoychev
@antitoxic
May 29 2016 11:46
I understand that.
Jean-Jacques Dubray
@jdubray
May 29 2016 11:47
No, all the questions you ask make sense and I understand what could be done to make it clearer.
I just looked at sam.js.org and realized that what we discussed about the view is not clear
Anton Stoychev
@antitoxic
May 29 2016 11:51
Also I was just thinking, having your example of parent-child SAMs - if I have 2 forms on the screen, both having a field "password", how do my parent model knows which form is calling model.present() ? In the example the check is done via: if data.username. This wouldn't scale.
And this is basically duck-typing
This is very curious for me. In Redux it's easy because all calls (dispatches) come with "type" which is an identifier.
Jean-Jacques Dubray
@jdubray
May 29 2016 11:56
Well, again, Redux does not decouples the "propose" phase from "accept" phase. For me that's a non starter.
Second, I prefer the "dataset" over "typed" actions for presenting data to the model
that is a preference because I feel this is the model efficient way, you have a many (action) to one dataset mapping, so you can have 10 variants of the same action and you don't need 10 types for it and you don't need your model to know about these 10 types
that's a very common case in OmniChannel applications as you would break your views differently on your mobile devices or Web app.
A lot of what you see as beneficial, from experience, I see it as a not so great design. You have to understand that behind SAM my goal is truly to achieve the maximum decoupling between the view and the model, to tying them via a "type" like Redux is doing it, is at best naive. Certainly I would not call that a good design.
Anton Stoychev
@antitoxic
May 29 2016 12:00
See, it's hard understand the answer of what I was asking. I still see critic. I get it but it doesn't help me.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:01
Well, as I said, I don't see Redux as being something that goes in the right direction. So it's hard not to criticize it. The only thing I like about React is JSX, everything else I would throw away.
Anton Stoychev
@antitoxic
May 29 2016 12:01
Great.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:03
I know it's a bit harsh, I can accept that I am missing something, but so far, I can't see the benefits.
Anton Stoychev
@antitoxic
May 29 2016 12:06

It's not harsh, it's just a bad way to teach - "your thing is shit, learn my better one". I would prefer "here's how you did it in your (shitty) way, here's how to do it in a better way".

Why are you still looking at benefits? I'm only comparing with Redux so that I understand. I just wanted to know how to do things in SAM in certain cases.

I'm literally on the edge of just quit trying though. This discussion is not a good experience for me.

Jean-Jacques Dubray
@jdubray
May 29 2016 12:08
Well sorry about that.
I can definitely see the issue with people having invested so much time in a framework and coming through that lens and me telling them, just throw away the whole thing. I get it.
Anton Stoychev
@antitoxic
May 29 2016 12:09
I'm ok with "throw it away"
I need alternative though
Not just base
Jean-Jacques Dubray
@jdubray
May 29 2016 12:09
Yes, I understand.
Anton Stoychev
@antitoxic
May 29 2016 12:10
I will trouble you with one last thing (i know i'm taking too much time). If my app initially had a registration form and my model checked the data via if (data.email !== undefined) ... and then I add a new feature - forgotten password form, how does my model's present() will distinguish between them?
Jean-Jacques Dubray
@jdubray
May 29 2016 12:11
The major issue with React/Redux is the "reactive" part makes it very opinionated for the overall programming model, so it is difficult to find room for a slightly different factoring.
You can trouble me as much as you want, I just may not have all the answers, especially the correct ones.
Anton Stoychev
@antitoxic
May 29 2016 12:13
Forgetting about React/Redux and everything else, how would I implement the above in SAM?
Jean-Jacques Dubray
@jdubray
May 29 2016 12:13
As I said, I prefer the dataset interface between actions and the model present method, but it is not always possible to have a pure dataset, so sometimes you have to put a type in the dataset, or even a control state. So the action would simply present a dataset such as {forgotten: true}
Anton Stoychev
@antitoxic
May 29 2016 12:14
Alright. Absolutely logical.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:14
this is neither a type or a dataset per se, you are directly specifying the control state to render the correct UI
Anton Stoychev
@antitoxic
May 29 2016 12:14
Will do tons of good in the docs.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:15
SAM gives a lot of flexibility, it is opinionated about just the mutation: propose, accept, learn everything else is "it depends".
It's also just a pattern, not a library per se. With SAFE, I am just trying to show people what's possible when you factor your code along the lines of propose, accept and learn.
Anton Stoychev
@antitoxic
May 29 2016 12:18
There was an article in the recent last 6 months saying something in the lines of "there is enough of "unopinionated" libraries and patterns out there, developers will spend hours and days figuring out the glue. A winning solution will give explanation how it all works together". It's cool that it's not opinionated but a good set of wiring examples feels like the only way to be accepted to me.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:19
So far, I have not seen a framework where I can say, that's it, that Framework makes it easy to implement SAM, so I generally use vanilla.js but the feedback I have is that people don't like it.
Well, I do see opinionated frameworks as a big issue.
Anton Stoychev
@antitoxic
May 29 2016 12:19
They are.
Though if you just tell me how the organs of the human body work and let me connect them, I wouldn't do a good job
I need at least an example of how they might work
Jean-Jacques Dubray
@jdubray
May 29 2016 12:20
I feel that SAM gives just enough structure without taking control of your code.
Anton Stoychev
@antitoxic
May 29 2016 12:21
Doesn't need to be a framework.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:21
But I hear your critic. I am thinking / will be thinking how to address it.
As I said, my biggest issue so far has been that I still prefer vanilla.js over everything else. Believe me, if I could say React or Angular are the way to go, I would do it without hesitation.
In the 90s I spent over 5 years of my life building a very complex solution using NeXTStep
One day Steve Jobs decided to throw it away (in 1997 as he returned to Apple).
NeXTStep was the React of 1990. It was something that an Alien ship had dropped on earth and looked like nothing we had seen before.
Anton Stoychev
@antitoxic
May 29 2016 12:24
Same danger goes for React and Angular, yes. But in order for people to learn you have to teach them with what they know or what they are excited about.
Jean-Jacques Dubray
@jdubray
May 29 2016 12:25
But... once you spend 5 years building something conforming to a framework and that framework goes away, you are dead. You throw away 5 years of your life.
I spent a lot of time trying to isolate myself from frameworks every since. "never again".
Yes, I understand.
Anton Stoychev
@antitoxic
May 29 2016 12:27
That's why vanillajs examples are not so well accepted.
I don't mind them but only because I'm close to abstracting away from frameworks myself.
I've also spend years developing in stuff I don't use right now :)
I don't think they are thrown away though.
reusability in general is very low due to rising expectations of usability
David Fall
@509dave16
May 29 2016 14:57

@antitoxic Sorry for the late response. I was asleep during your chat with @jdubray.

1) SPINNER: With concerns to controlling the aspects of UI elements(such as a spinner), I can see how it's bad to have a Model Property called 'showSpinner' as that would pollute the Model with UI details. In fact in my project(https://github.com/509dave16/sam-tic-tac-toe), uses one such property called 'showJoinSessionForm'. It is possible for me to remove my reliance on this Model Property and to instead rely on deriving the visibility in a Container Component that wraps my Form Component. For instance, I could have a State called JoinSession that is true if gameType === 'Join Game' and session === undefined. Those two conditions that make up that State should be enough to assert that the Form Component should be displayed. Once the Model accepts a valid 'session' key, the JoinSession State is no longer true thus the Form Component would not be rendered.

2) CANCELLING SPINNER: As for the user deciding to cancel an Action that should result in the Spinner no longer being displayed, I would recommend you somehow mutate the Model to revert to a State that would not indicate that the Spinnner should be displayed.

3) PROP PASSING: As for passing all the Model Properties as separate props down through the Component Tree, I would recommend having Container Components that connect to the Redux Store and they will decide which Model Properties need to be passed/mapped to Presentational Components.

If there were any questions that I missed or misinterpreted let me know. I would be more than happy to answer them to the best of my ability.

Jean-Jacques Dubray
@jdubray
May 29 2016 21:17
@509dave16 @antitoxic thank you Dave, that is really the essence of the pattern, you want to keep the model as clean and tidy as you can and minimize its knowledge of the application specific logic which should be coded in the Actions and the State.