in v5, there was only dragging, and changing the width in the inputs kept a perfect aspect ratio. but for v6, i had to track both width & height for full sizing control. initially, i used nap() to loop thru all sprites after each render to see if any sprites had no height set (since i was letting the browser do the heights previously, and only settings widths) -- if there was no height, that would mean it was a freshly added sprite and i needed to wait for its image to load and then read its height and set it on the sprite. so waiting for assets to load and then parsing/reading/whatever from them seems like a good "automatic action"

it was funky at first, and i was kicking off a caculateSpriteHeight action in the state function, but also using jquery to wait for the sprite's image to load and in the callback kicking off another doneCalculatingHeight action. but then i realized probably i only needed the former action in there, and all that other jquery stuff could be moved out into the calculateSpriteHeight action itself. wasn't sure if that was a bad idea -- presenting to the model, but also kicking off another action after some async occurred

but then i realized by the time the user is ready to resize the thing, the image is already loaded anyway, and instead i could just read the current height of image when converting mousedown into appropriate actions -- so now in mousedown i figure out which sprite's grip i'm clicking on, inspect the DOM to find the sprite's image's current height, and then fire both a setSpriteHeight action with that height, as well as the beginSizingSprite action. a sort of JIT setting of the height i guess, heh

I would not say "centralized", it's more like "deliberate", the step during which you mutate state must be delineated. You can't arbitrarily/liberally assign property values. That is (IMHO) what's wrong with the way we write code.

That is the biggest problem with two-way binding (Angular, Vue and others).

I really don't see the need for nap() to be involved. That's kind of the big value add of SAM, you need to inform the application state of what's happening (unless it logically requires that you do so)

@chuckrector 's problem is that the sprite is added but without the correct width/height, possibly causing some UX issue. From a SAM pattern's perspective, the side-effects start with whoever needs to "learn" from the mutation. As I said, it's kind of obvious, you need to reach a stable "state" before other elements of the program can do "react" to it, but that's not obvious to achieve in practice.

You quickly get lost as to what a "stable" (i.e. mutated) state means.

Yes, yes! It's a huge win in SAM to control mutation and the reactive loop, without tying together the model and the means of controlling mutation. I am trying to say that, although the "model" in SAM controls mutation, the model data itself does not, i.e. it is a plain simple JavaScript object. IMHO this is the problem with observables, RxJS, MobX etc. The model data and the way of controlling mutation are mashed together, and suddenly you have to use these specific types of objects for your model instead of plain JS objects.

Instead of having these special observable objects along with their APIs etc, you just present a proposal to the model, the model handles mutation, and the state provides the representation. The actions and view are totally decoupled, they don't need to know about anything other than plain JS objects.

I did a quite large project with CanJS (a few years ago, which are decades in JavaScriptLand), and, although it lead to better code at the time, the one thing that was a real drag was that you had these observable objects instead of plain JS objects.

I find it a much saner way to write programs, to follow the very clear present/accept/learn loop rather than observable.setValue/magic happens/things get updated/no idea of all the impacts.

Another testimony to the sanity of SAM is, how easy it is to write a tracer/devtool/time-travel tool vs writing one for cyclejs (for example).

I understand/agree with all of the above but I still don't get this "arbitrarily/liberally assign property values". SAM guarantees that state1 -> state2 transitions are valid bc it has access to the whole model (its centralized). I don't see how it would do that if that wasn't the case

There is no concept of "centralization", this is just a common/safe way to implement the pattern. I can have parent/child instances, I can even have several present running in parallel if I know what I am doing. it should rather be viewed as a protocol with clear roles and responsibility.

All you need is the relationship proposal / unit of mutation / state representation, there is nothing that says that every proposal has to see/impact the entire model. There is absolutely no requirement for that. Again this is just a common way to implement SAM.

I could implement SAM with a bunch of proposal/unit of mutation/state representation, it's not a good coupling, but I could couple proposals with units of mutation and the parts of state representation they impact.

honestly, I think it is a bit hard to understand these concepts (specially where you can have multiple implementations) without concrete implementations and examples -and what implications designs you have until you implement it in concrete examples and/or large scale. But this is interesting " could couple proposals with units of mutation and the parts of state representation they impact." is there an example of that?

it just means your have several "present" methods that could potentially execute in parallel because the units of mutation/state representation independent.

You can imagine a dash board each widget is kind of independent of each other. You could decide to have one big model behind the dashboard or one per widget. As long as the actions on one widget does not have implications on another, you can keep everything separate. Same thing for a game, you could have different independent planes without interactions between them.

Again, there is no requirement for centralization, this is just a better way to implement the pattern, because in general the units of mutation are not that isolated and their boundary can change over time, it would make it harder to refactor over time.

However, there is no conceptual reason for having a centralized model.

the way the SAM patterns work is proposals (prepare) -> units of mutation (mutate) -> state representation (propagate the result of the mutation)

@rickmed Please look at it from the most basic point of view, SAM simply encourages you to group assignments in "units", no other parts of the code can make these assignments and no other parts of the code can see these assignments until the unit is complete.

as @foxdonut you could enforce that with specific types such as "observables", "streams" or "immutables" but that brings a lot of constraints to what you are trying to do, they don't make these problems go really go away, especially RxJS.

yes it is, each time an automatic action needs to be triggered, it needs to happen at that point in time, but you don't need a "centralized" decision process. You just can't trigger an action in the middle of a mutation, that's why I say SAM is closer to a protocol, rather than a structure.

@jdubray yes, it would make sense to load the image dimensions as part of an addSprite sort of action

though that would also require me to make some changes to my initial model that hydrates the real model. but that is i suppose because the new requirement of height for each sprite would make my current initial model data invalid

that is, any image has its "natural size" and in my data i am only passing a single "desired width" as a proxy for a scaling percentage. so in v5 the height of the sprite's image was always implicit and irrelevant to UX -- you just specified different widths and the image would naturally scale according to its aspect ratio, as a result of the fact that browsers auto-size a non-specified dimension in proportion to any specififed dimension

in v6, height is now important because you can size any sprite's image arbitrarily, ignoring its natural aspect ratio. the funky states i got into were surely a result of just hacking away instead of stepping back to think about the impact of the new UX on the model

now that sprite height is a "first class citizen" that means i should... update my "initial model" to include heights too. normally, any initial model you would use to hydrate your app would have been the result of a previous saved state, and this wouldn't play mind games. but on a small toy example, since i have handcrafted the initial model myself, i have to keep a close eye on what i am trying to perform my initial model population with... since the initial assignment is basically one huge unchecked mutation of state

i should probably be validating that initial model used in hydration, now that i think about it. though, again, i suppose it is only a problem because i am handcrafting the initial model

i should actually design a UX for this thing! rather than ad hoc experimentation. i'm sure no (good) UI for sprites ever had only a width input without the height, heh. you know, i think it's really easy for engineers to get into weird tunnel vision states due to being accustomed to executing on many small assigned tasks, versus exercising holistic bigger-picture reasoning skills that come with designing a full app and a coherent UX

yes, really understanding the work flow is key to a successful UX. I am not sure I understand what you are building, I thought you were just playing with the model / state representation and you needed a GUI to simulate actions. Are you trying to build some kind of design tools for games?

no, you're correct -- it is playing around, but with the aim of exercising and understanding SAM better in practice. i wanted something more complicated than "foo bar baz" but not perhaps a full-blow application, just a nice in-between of medium complexity

as far as what it is exactly, i was thinking just a basic 2d scene compositor. like flash without animation. or maybe adding animation eventually

while it is easy to understand the basics of SAM on paper, it is a little more complicated in practice, so i want to keep going and building this out until i feel as though i have a decent grasp in practical terms of how to build things using SAM

well, i shouldn't say complicated in practice necessarily. nothing i have encountered has been complicated in terms of SAM. it's more in, i guess, firming up the "ratios & responsibilities". what things are better to go in actions, what things are better to live in the model logic, etc.

then I would clean up the relationship between action and model. I would definitely present a new sprite with height and width for instance. The model could still tweak these values, say with a default zoom ratio, that's the advantage of action/model, you would not want to action "add sprite" to know what's going on.

the node/browser divide is an interesting one. i can include jquery in my main app.ts via imports and wire up various events with it and it's great. but if i wish to use jquery as part of my onClick events that are generated in the view, i must also include jquery in my index.html via script tag

i suppose alternatively instead of having all my views as string generators, they could generate actual elements

it seemed quite complex to me for a while. and various articles and the webpack docs themselves seemed to confirm that

however, if you read through the docs a bit and in the user comments, they direct you to an article/tutorial which describes what exactly webpack is and how it works and how to use it far better than the actual webpack documentation

cool, i will check out ng2 then. i have not tried any angular at all yet. but many candidates for FE i have interviewed have experience with it, so it would probably be useful for me to get some familiarity

I truly find Angular2 a pleasure to work with. It takes a bit of time to get all the pieces together at first, but once you have them, then TypeScript keeps it manageable. I would not have the same opinion without SAM, because they have a weird component programming model with parent/children and all the two-way databinding. SAM cuts through all that.

yes, it took me a couple of weeks to get comfortable with it. Can't claim I know everything, but once you get your project in place you feel that's really easy to add to it. I even figured out how to compile dynamic templates.

as I said, sometimes you just can't explain it, on paper ng2 would be everything I dislike, it's just once you try it, you feel it's pretty logical (minus two-way data binding and parent/child components).

Since you said "on paper ng2 would be everything I dislike" then I understand, how perhaps "sometimes you just can't explain it" and you were able to make the best of it with ng2 and avoid the bad parts.

The State function shows how important it is to decouple the View from the Model. All this code would be hard to fit in the model or the view. It really keeps the view and the model simple, without making the state function that complex either.

The wiring is never a big problem with SAM. The State function is a (true) pure function that takes the model as an input and return the state representation. It's irrelevant whether it is wired in a reactive loop or not.

you can imagine the newGif component like this: there is a search bar in which you type "cats" and it shows in the ui a card with a random gif (from eg giphy.com) related to cats. Everytime you search for a random gif, a new card is added to the ui

@jdubray do you mind elaborate on this "In the sample I decoupled the update (of the model) from the reactive aspects of MobX, which IMHO is a lot cleaner than implementing the mutation with computables."?

@rickmed what is "A pair of RandomGif" and "A pair of pair of RandomGif"? Why are they issuing actions like TOP_LEVEL_RANDOM_GIF_UPDATED and FIRST_RANDOM_GIF_UPDATED? Why can't RandomGif just be a single, reusable component and you can just put as many instances on the page as you want?

the question is, could I package let's say 2 sliders (that is just an example of delegating some part of the ui to a team), as a standalone app without changing the internals of the sliders? if not, then it is not fractal

btw, the overall problem at hand is a question to fractal architectures themselves (like redux or cycle js)

put this way: could I compose a component which is 2 sliders (composed by 2 separated slider componentes) to add 2 sliders at a time instead of one?

@rickmed the principles behind MobX is to use just observables and computables, but when you assign the value of an observable the computables recompute. SAM forces you to hide all the assignments until you are ready to create the state representation. I like that better, I don't like the model to "observable" like Redux's store or MobX. In the sample the State function is responsible for translating the model into observable values. Then all the magic can happen, and then nap().

yes! when you see consecutively running lines of code in JS they always happen without pause (unless you are using await, which is in a future spec of JS). when you pass a callback, that's usually when async stuff can occur.

there is also this concept of mobx strict, when enabled, only mutations to observables are permitted inside an "action" function, an action function is wrapped automatically in a transaction, a transaction lets you mutate the model several times and only let the computed/observers react when it is done

yes, ideally after the state representation has been displayed by the view, but there could be some optimization when you know an action is going to be triggered and you don't display until the next-action completes.

It's a pattern, not an exact formula to follow. I really just want to provide some structure so that we don't rely on a library like React or RxJS to define the programming model.

if you want to represent SAM mathematically is not going to be that simple (at least for the non mathematician to understand), bc most of the functions (at least as I see it simply in the launcher example) are not pure (don't return anything). On the other hand, is cool that SAM is implemented with plain old functions, and is reactive, meaning, the whole thing is a recursive pattern, which you could represent mathematically but not like x = f(y)

from my understanding, it is still valid SAM if i make my state function return an object of StateRepresentation, then immediately after I call view.render(sr). its important to move this outside of the state function imo

each component has its own state-representation, but there only needs to be one render()

@edmulraney I would disagree, each component has its prop, it is the state function which decide the shape of the state representation. You cannot have any business logic in the view. The view is pure component/display logic.