These are chat archives for jdubray/sam

11th
Apr 2017
Fred Daoud
@foxdonut
Apr 11 2017 12:22
I have started writing tutorials and recording short screencasts for Meiosis 1.0. The first five tutorials and first two screencasts are available: https://github.com/foxdonut/meiosis/wiki
More to come!
Jean-Jacques Dubray
@jdubray
Apr 11 2017 12:53
:thumbsup:
devin ivy
@devinivy
Apr 11 2017 12:56
i have begun thinking of nap() as a way to "pull" missing data. i'm starting to feel weird about views firing off actions when they think they need to load themselves more data. why not let the app respond to some data being missing? e.g. if i have a piece of state currentPost referencing a post id, and that post id doesn't have an associated record in state allPosts[currentPost], then the app goes ahead and requests the currentPost from an API or elsewhere.
anyone played with something like this? is nap() the way to go there?
Jean-Jacques Dubray
@jdubray
Apr 11 2017 12:59
Views should be as dumb as possible... The State function (with nap) should be doing all the heavy lifting. Any logic you feel should be in the view:
a/ for rendering, should be in the state function
b/ for doing something (such as JQuery calls, fetching more data, ... ), should be in nap
There should be absolutely no app logic in the view. That's a rule that can't be broken at all.
devin ivy
@devinivy
Apr 11 2017 13:03
yes, there's no question about that. i wouldn't anticipate any app-logic in the view, but (in redux-land) the view would be connect()ed to live actions. the view would simply express its need for a post to be made available to it. (this is all in the non-nap() case.)
for example, imagine going to a route /post/:id
the main component for that route might fire an action obtainPost(params.id).
my revised idea would work differently. instead a piece of state would change currentPost to params.id. then nap() would see that there is no post in the app yet by that id. so it would fire getPost(currentPost)
Paolo Furini
@pfurini
Apr 11 2017 13:06
@jdubray but saying should be in nap it is the same that saying it should live in the action code.. I mean nap is simply a way to trigger one or more extra actions when processing state, or I missed something special re NAPs?
devin ivy
@devinivy
Apr 11 2017 13:07
@pfurini i don't think nap() is reducible to action code.
it's a re-action to a change in state.
the actions will not know if state is going to change, and they certainly don't know how state will change.
Paolo Furini
@pfurini
Apr 11 2017 13:12
in fact actions will not fire a next-action, only a state function.. in the simple rocket launcher example, I think of the launch action as a next-action when processing counter state change. But factoring that launch action as a normal callable action, one can re-use it, for example, by adding a super-user Launch button that can trigger the rocket anyway. The model (in the propose phase) could accept the state change or not, but you should not bother about it, you should be free to trigger the launch, and see what happens.. this is what I think of a highly decoupled architecture
Paolo Furini
@pfurini
Apr 11 2017 13:21
So in your example, when the state function receive the updated model data, it should prepare the state representation for properly rendering a target view pre-requisites (in terms of mandatory/optional inputs). If among the mandatory inputs there is some other data not currently available in the model (for example post details, or comment stream, etc.), it could render the view in a "partially loading" state, then it should fire a next-action to fetch the dependent state, that in turn will trigger the Propose->Accept->State(Render) pipeline. The same state function will be executed, this time with the full state, and the view will be rendered fully and not in loading state
I simply don't see the need for "special" acting next-action semantic
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:22
nap has the logic to decide what to do next
what actually happens is in the action
@pfurini yes, exactly actions are highly reusable
Paolo Furini
@pfurini
Apr 11 2017 13:23
so it's simply a way to move the decision logic outside of the state function..
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:24
You don't need to know where the event that triggers it came from
@pfurini yes, this is the kind of behavior you can do. The problem with server-side rendering is that it's harder to give this kind of user experience with partial rendering/loading.

I simply don't see the need for "special" acting next-action semantic

it's not always from the point of view of the view, next actions can be triggered for a lot of reasons.

Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:31
It's not practical to "think" and code in terms of state machines, that has been proven over and over, and I don't challenge that. All I am saying is that rarely (1-2% of the time) you need to think in terms of state machines, that's when nap is used.
partial rendering / loading is one of these situations, you can't lose track if where things are at. I use facebook a bit and you can really see how they struggle with their "state". A couple days ago I had messenger opened and I tried to post something, it would let me start the post, try to open the editor, then everything would go grey. I tried a few times until I started to think that the little messenger window at the bottom of the page was the problem, I closed it and then I could post.
Paolo Furini
@pfurini
Apr 11 2017 13:33
Sure, they should be generic and reusable, like you said.. So in that regard a NAP is simply the logic that, given the state needed, triggers one or more actions. What to reason about, is the sync or async flow of that process..
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:36
yes, the rendering need to be thought about, just like in the facebook example, as you re-render after a nap triggered action, the user might have started an activity that will be impacted by the re-rendering. That's where the pub/sub mechanism Angular supports (though I rarely see it used that way) is really good because you can control very effectively how the re-rendering happens. I would not be surprised if that mechanism becomes more popular as people see its benefits. That's where React fails IMHO, it offers a very "reactive" mechanism with very little control.
Paolo Furini
@pfurini
Apr 11 2017 13:38
That's the same in Aurelia, only more powerful (his author was the source of the best ideas in Angular 2, before he left)
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:39
well, if you can somehow implement one-way data binding then that's good. The only part I don't like about Aurelia is the V->M binding, that is not fundamentally flawed.
M->V is not much better...
Maybe you can use Aurelia in an MVVM fashion, where the Model is just the Model of the view where you publish props and you translate updates into events. That's a lot of useless work IMHO, but for large scale apps, I don't see any other possibility.
Paolo Furini
@pfurini
Apr 11 2017 13:41
Well, Aurelia has the benefit to be highly decoupled. Its packages are independent, and reusable to build your own framework. The downside is that this modularisation is not advertised and well documented
I mean, you can pick only the DI hierarchical containers, the binding system (it supports one way data binding, event flow binding, etc.) and swap the rendering with yours..
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:43
I see, yes that's not apparent at first.
Paolo Furini
@pfurini
Apr 11 2017 13:43
But I admit is not a fast start, given it's not so well documented for the uninitiated
But I have other concerns, like the "single state source of truth" principle at the heart of FRP or FRP-like architectures..
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:46
That's the problem we all make decisions on small samples it's very hard to see how this will scale to large apps. The largest app we've built this far is with Angular2 that's why I can confidently say that SAM can scale, but the user experience was not the most modern. As I said we struggled to find a nice date picker, which with JQuery is a piece of cake.
"Single State" is not absolutely mandatory, as I said, you could use SAM to implement controllers. I like the "Single state" aspect, but I see it's limitations as well. Just like parent/child SAM instances, you can decide the granularity of a single instance. You can substitute instances below the view (an action can talk to a different one).
React/Redux has a strong requirement on single state tree because of the dev tools (Time Travel). That's ridiculous that you architect something just to be testable. It's an important concern, but still secondary.
Paolo Furini
@pfurini
Apr 11 2017 13:49
The only problem I see is state reconciliation at upper nodes of the "state tree"
But maybe that's a false problem.. I should not reason as a state tree, but logical pieces that communicate with actions, or pub/sub, queues etc.

That's ridiculous that you architect something just to be testable.

yeah, that was exactly what I thought

Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:52
yes, I think that's a better way to think, what's more important is that only one component is responsible for updates. As long as all the instances can be "coordinated" then that's the outcome you are looking for, it's not important if it is in a single state tree.
I bet that was the problem #1 at Facebook they lost control of their unit tests and Redux brought back some sanity and they called it a day, they never looked back as to why they had lost control.
devin ivy
@devinivy
Apr 11 2017 13:54
time travel thru actions is hard for me to give-up now that i have it...
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:54
ah ah
devin ivy
@devinivy
Apr 11 2017 13:56
that said, i can deal with reasonably coarse levels of granularity. i don't need my scroll bar to be time travelable :laughing:
Paolo Furini
@pfurini
Apr 11 2017 13:56
If a large app needs to read/write to a single state "bag", I can't see it as scalable and maintainable in the long term..
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:57
@devinivy so disappointing...
devin ivy
@devinivy
Apr 11 2017 13:58
what is disappointing? the fact that it's hard for me to give-up time-travel?
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:58
I may not recalling properly, but NeXTStep in the early 90s already had a NXJournaler that was pretty much time travel and it worked for scrolling too.
devin ivy
@devinivy
Apr 11 2017 13:58
haha :D
Jean-Jacques Dubray
@jdubray
Apr 11 2017 13:59
No the fact that TT does not work for scrolling, I had TT that worked for scrolling in 1992
25 years ago...
devin ivy
@devinivy
Apr 11 2017 13:59
i mean, it can work for scrolling!
i certainly wouldn't need that.
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:00
@pfurini yes, I agree. It must be modular in some ways, but not all modular approaches are the same.
devin ivy
@devinivy
Apr 11 2017 14:00
without special treatment, it would dilute the other actions in history.
Paolo Furini
@pfurini
Apr 11 2017 14:00
I expect to see namespacing/partitioning appear at some time in the state data, because of independent work done by some dev.. something like, "i need to track state for this part, let's create a sub-node.."
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:01
@pfurini IMHO, this is taken care of by the many-to-many relationship between actions and acceptors. Different teams can work on different kinds of acceptors.
That being said, assembling the acceptors in a working/maintainable way still needs to be realized
Paolo Furini
@pfurini
Apr 11 2017 14:02
But the state then should be isolated from acceptor to acceptor
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:03
well, yes and know, in the model you are isolated, that's why people like functional programming because a function provides that level of isolation.
You can modify the state as much as you want, as long as no one else can sees it, when it's consistent, then you can pass it on.
That's what is killing OOP IMHO
Paolo Furini
@pfurini
Apr 11 2017 14:05
Ok, but nevertheless the model data should flow from fn to fn.. If it is your single source of truth, you'll soon start to fight collisions
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:05
yes, no question.
devin ivy
@devinivy
Apr 11 2017 14:05
right– this is what the state factoring is for in SAM, in particular
this is one of the least understood and most important principles
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:06
As I said, there has to be a "coordinator" or some self-coordination to mutability.
devin ivy
@devinivy
Apr 11 2017 14:07
i still think we really need an adapter-based store, that can be immutable or mutable.
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:08
@devinivy yes, that's probably the part I am the proudest about SAM. In the end there is a static and a dynamic aspect to application state, SAM decouples them as the Model and the State function.
devin ivy
@devinivy
Apr 11 2017 14:08
:thumbsup: changed the way i think about things and has made my life easier– definitely appreciative for that!
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:08
It's not a good idea to mash up these two aspects in the same code base.
Paolo Furini
@pfurini
Apr 11 2017 14:08
but the state function is responsible for adapting the model data to a state representation suitable to be consumed by listeners (being views or whatever). right?
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:08
:+1:
devin ivy
@devinivy
Apr 11 2017 14:08
@pfurini yep!
also calls nap()
i guess that fits into your "or whatever"
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:09
yes, but that happens as a result of the "state" (status) of the application state.
Paolo Furini
@pfurini
Apr 11 2017 14:09
what I'm criticising here is the Acceptor/model part
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:10
In TLA+ that's the "temporal" part. The model should have no "temporal" aspect (dynamic).
The model should be purely static, here is a proposal, can you accept it?
devin ivy
@devinivy
Apr 11 2017 14:11
in a perfect world i think there would be an action (basic intention), translated into a proposal (model mutation), and that would be passed to the model for acceptance (or not).
sometimes it feels like too much work to turn an intention into a mutation separately from the model, so it all happens in the model at once.
Paolo Furini
@pfurini
Apr 11 2017 14:12
I always architected my models that way, I'm simply worried about the data consistency when dealing with a single state bag
devin ivy
@devinivy
Apr 11 2017 14:12
it's not as big of a deal as the delineation between model and state, in my opinion.

I'm simply worried about the data consistency when dealing with a single state bag

can you give an example?

Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:13
The State function should not perform any mutation
Or if any update parts of the model that the model do not touch such as the current state/status of the system.
If you look at it from a micro-container point of view (SAM-SAFE), technically in the State function you have not completed a step yet, so it's still ok to perform mutations, but I would suggest to avoid it
devin ivy
@devinivy
Apr 11 2017 14:15
presumably that's what nap() may cause.
it could lengthen the step
and cause more mutation
it might sort of correct a glitch before the glitch makes its way to the views.
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:17
yes, that's why nap should return true/false as to whether a next-action was triggered, that indicator could be used to decide whether to render or not (assuming you render after nap-ing)
Paolo Furini
@pfurini
Apr 11 2017 14:20

I do really see the value of all the parts of the architecture, and I think I can start implementing it (based on my little experience in the plunker I posted). What worries me is simply the state object/bag or whatever (basically, it's 95% of the time a simple POJO), that is often referenced in reactive examples like this (I selected this example simply because I just read it..):

The Top-Level Model

The first thing we'll do in Meiosis is have a single source of truth. This is the top-level model. This model contains the data that we need to produce our user interface, or "view".

Let's build a simple example where we have a Temperature value that we can increase by pressing a button. The model for our example is:

const initialModel = {
value: 20
};

Precisely this sentence:

The first thing we'll do in Meiosis is have a single source of truth

devin ivy
@devinivy
Apr 11 2017 14:22
what worries you about that in particular? any good examples?
Paolo Furini
@pfurini
Apr 11 2017 14:23
That example is something like 10 LOC.. How will that single model data bag look like for a 10K LOC app?
Prediction: a big mud of potentially collisions
devin ivy
@devinivy
Apr 11 2017 14:24
you're worried it will get large and messy? it's still a tree– it can still be broken-up into different branches.
i'd say it's more of a tree than a bag.
Paolo Furini
@pfurini
Apr 11 2017 14:26
Then you ran in the same namespacing problems that other approaches have.. you should take care to avoid branch naming collisions
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:27
sorry have to go to a meeting
Paolo Furini
@pfurini
Apr 11 2017 14:27
There is no clear separation, and if you adopt the clone and mutate for every change, it could get very inefficient
Jean-Jacques Dubray
@jdubray
Apr 11 2017 14:28
You should talk to @dagatsoin he is currently implementing SAM at that scale
devin ivy
@devinivy
Apr 11 2017 14:29
distributing state seems like it introduces even more opportunity for inconsistencies. at the end of the day your app requires a certain amount of state to render its interface for the user– you have to organize it somehow. avoiding a branch naming collision luckily can be solved at each level of the tree, not in the totality of a "state bag." i wont stand-up for clone-and-mutate approach because i don't love it. however, its inefficiency is proportional to the depth of the tree, not the entire size of your state. that means roughly log(n), which aint the worst.
Paolo Furini
@pfurini
Apr 11 2017 14:30
@jdubray thanks.. have a good meeting :smile:
I see.. the clone and mutate approach is standard in FP solutions, like Elm
devin ivy
@devinivy
Apr 11 2017 14:34
that's because of the fascination with immutability. i think our fascination with immutability is a side-effect of using react, which heavily prefers direct pointer comparisons. and the fact that FP is an approach to deal with multi-threaded environments. but this is javascript!
i like the principles of FP in general, but the immutability thing mostly drives me nuts :P i use it to keep react happy.
in polymer, for example, i use direct mutations, because polymer is designed to handle that.
Paolo Furini
@pfurini
Apr 11 2017 14:39
immutability by itself buys nothing.. it's when used with the right "tools" that can prove its value. It's certainly not a panacea, like many advocate
devin ivy
@devinivy
Apr 11 2017 14:41
agree!
Paolo Furini
@pfurini
Apr 11 2017 14:46
but can you resist to the Rich Hickey's charm? https://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey
one of the most famous and enlightening talks on FP benefits (a bit biased, but fascinating)
Fred Daoud
@foxdonut
Apr 11 2017 14:49
@devinivy
i have begun thinking of nap() as a way to "pull" missing data.
what you said earlier, yes indeed I thought of that too, what you said earlier.
I experimented with that, e.g. in a UI with tabs, if you switched to a tab, nap() would look if there was any data for that tab, if not, fire an action to load it.
Result being to load the data the first time, but not again if you switched to another tab and back again.
devin ivy
@devinivy
Apr 11 2017 14:51
:thumbsup: so you like it?
@pfurini i will check that out
Fred Daoud
@foxdonut
Apr 11 2017 14:52
I do.. still experimenting with other ways though and have not decided which is best
devin ivy
@devinivy
Apr 11 2017 14:52
@pfurini i loved his "simple made easy"
Fred Daoud
@foxdonut
Apr 11 2017 14:52
@pfurini
devin ivy
@devinivy
Apr 11 2017 14:52
@foxdonut what are some other approaches?
Fred Daoud
@foxdonut
Apr 11 2017 14:52
That example is something like 10 LOC.. How will that single model data bag look like for a 10K LOC app?
Indeed as @devinivy it is a tree
And, what I am going towards is that you can break it up
each logical part of the app has it's own (sub) model
Paolo Furini
@pfurini
Apr 11 2017 14:54
@foxdonut exactly what I wanted to hear.. :smile:
Fred Daoud
@foxdonut
Apr 11 2017 14:54
so the top level might look like
const initialModel = {
  user: user.model(),
  location: location.model(),
  books: {
    active: activeBooks.model()
    ....
  }
};
Paolo Furini
@pfurini
Apr 11 2017 14:54
yes, that seems reasonable and manageable
Fred Daoud
@foxdonut
Apr 11 2017 14:55
each component deals with its own submodel and does not need to know where it is nested within the top-level model
I will be adding more material to https://github.com/foxdonut/meiosis/wiki about all this :)
The top-level code manages how to merge changes back into the top-level model
You are free to use plain JS, Lodash, Ramda, Immutable.js... whatever makes sense for you.
@devinivy for example, with routing, listening to route changes
Paolo Furini
@pfurini
Apr 11 2017 14:58
In a dynamic composable interface, the sub branches could potentially be totally independent.. I'm thinking of pluggable architectures
Fred Daoud
@foxdonut
Apr 11 2017 14:58
@pfurini yes! in my experiments, you can take a "component" and reuse it more than once, in different parts of the top-level tree, move it around etc. and it works with no changes to the component itself.
devin ivy
@devinivy
Apr 11 2017 14:59
@foxdonut i see that as being very similar. the route is part of your app-state (whether it's in the URL bar or reflected in your model), so loading data based upon changes to it seems very similar to responding to model changes in nap().
Fred Daoud
@foxdonut
Apr 11 2017 15:00
@devinivy I agree!
devin ivy
@devinivy
Apr 11 2017 15:02
i'm going to play with this, and hopefully report back before long!
Fred Daoud
@foxdonut
Apr 11 2017 15:02
@pfurini so I'm assuming you had a look at the wiki.. did you just glance at the text? did you use the codepen? just wondering if it's useful.
Paolo Furini
@pfurini
Apr 11 2017 15:05
I glanced quickly TBH.. I'll re-read it ASAP, it looks promising. I had a look at the code before, and some examples, but I need to try it to really grasp it
Fred Daoud
@foxdonut
Apr 11 2017 15:16
Agree, that is why I set up the codepens, I want people to experiment with the code, it's the best way to learn.
Paolo Furini
@pfurini
Apr 11 2017 15:25
:+1: BTW, I like codepen, but I found plunker a more complete solution for more complex PoCs
I like the way I can add files like in a real project..
Fred Daoud
@foxdonut
Apr 11 2017 15:43
true, and I've seen other similar, more complete options
might use them when the examples grow past the point of being manageable all in one place.
for example, https://codesandbox.io