These are chat archives for jdubray/sam

28th
Jul 2017
Janne Siera
@jannesiera
Jul 28 2017 09:38
@jdubray thinking of SAM as factoring and decoupling of event handlers seems like a decent value proposition to me. The problem: event handlers are too tightly coupled to both views and application state. And thus hard to reuse and reason about. The solution: decompose into actions, model manipulation and view manipulation.
Does that sound right to you?
Another question: why are actions not allowed read-only access to the model's application state?
Janne Siera
@jannesiera
Jul 28 2017 09:55
e.g. when updating a counter the counter_value gets passed model -> view -> action (which increments and proposes to model)
Intuitively, I would skip passing the counter_value through the view, and instead have the action read the current counter_value from the model
Nivani
@Nivani
Jul 28 2017 10:52
We will have to see what jdubray says, but I think your view will have all the data it needs to call the action because it should receive a state representation that contains everything it needs to operate properly.
This way you do not create any direct dependencies between your actions and your model. The only thing your action needs to know is how to make a proposition to the model, not how it is structured or anything like that.
Jean-Jacques Dubray
@jdubray
Jul 28 2017 11:02

decompose into actions, model manipulation and view manipulation.

So technically there is no view manipulation, the state function computes the state representation, i.e. the properties that need to be passed to the view to render, and the next-action if any. That's important because otherwise there is no good place to put that logic. It does not belong to the model nor to the view.

Jean-Jacques Dubray
@jdubray
Jul 28 2017 11:12

why are actions not allowed read-only access to the model's application state?

The theory behind it is that you want to be careful about concurrency issues. You cannot be garanteed of what the model is currently doing, it might be processing a proposal and therefore it would be hazardous to get any value. I know that JS is single threaded, but you can still have concurrency issues depending on the type of async operations your actions and model would be involved in.
It's better to create the proposal based on the state representation the action was triggered from.

As @Nivani mentioned, circular dependencies are not desirable, a reactive loop is easier to reason about:
event -> action -> model -> state -> view -> event ...
                              |------> event -> (next) action -> ..
Jean-Jacques Dubray
@jdubray
Jul 28 2017 11:17
In practice it's not too hard to achieve. I do use a few global ~constants (say endpoints of API calls).
I don't want to say that all the rules are set in stone, as long as it does not hurt your ability to reason about the code, but for me, clearly a reactive loop is a lot easier to reason about compared to inter-dependencies.
It also moves the center of gravity of the action towards the event, rather than the model like in traditional MVC. The action's role is to validate, enrich and transform the event (such that the view is not burdened with these operations).
Jean-Jacques Dubray
@jdubray
Jul 28 2017 11:24
As I said before, when you take the action to add water to a glass, or start your car in the morning, does the action know the volume of water in the glass? Do you (as the origin of the event) "get" all property values of your engine (if any) to execute that action? (modern cars have a two step starting process: first power the car and give a state representation, then allow the user to start the car)
There is no practical reason for the action to query the model, I could call that an anti-pattern.
Nivani
@Nivani
Jul 28 2017 11:30
@jannesiera in your reasoning about the counter example you say that the action increments. That would mean the action calculates the new counter value and that is probably the reason you would want access to the model there.
That action should propose to increment, but not calculate the new counter value. You can see it here: https://github.com/jdubray/sam-samples/blob/master/react-counter/index.html
It's similar to jdubray's example of the glass of water.
Janne Siera
@jannesiera
Jul 28 2017 12:09
I was taking a look at this example: https://bitbucket.org/snippets/jdubray/9dgKp/sam-sample
And here the action seems to be decrementing, but still has to propose to the new value to the model.
Victor Noël
@victornoel
Jul 28 2017 12:10
in the end, it depends on your business domain: toy examples are a bit limited to reason about what is the best course of action
Jean-Jacques Dubray
@jdubray
Jul 28 2017 12:16
@victornoel totally agreed, it's very hard to reason about a few lines of code and provide general guidelines. All I can say is that I have now code two big projects and many small ones using SAM and I never had to fight its semantics and only got burnt when I took some short cuts. As I mentioned before I can explain what's different about SAM and other approaches including Redux, but you have to look precisely at the semantics, of each approach.
@jannesiera that's a very old sample. I am not accessing the model, I am just computing the new counter value from the event (which came from the model of course), but from a concurrency perspective, it's not a good choice to do it that way.
Nivani
@Nivani
Jul 28 2017 12:20
I was also confused about this when I first started looking at SAM
Janne Siera
@jannesiera
Jul 28 2017 13:44
@jdubray I see. Because your actions are not directly mutating the state but merely creating proposals, you are introducing a concurrency issue? Where 2 actions, both trying to increment a counter_value by 1, propose the same value of counter_value+1. While the intended behavior would be to increment counter_value twice, resulting in counter_value+2
So, instead of proposing 'new values' to the Model we propose Commands instead? (not unlike CQRS?)
Jean-Jacques Dubray
@jdubray
Jul 28 2017 13:55
you don't have a choice for "additive" operations (add to a list, add to a value...)
that being said, SAM is somewhat different on the Q side of CQRS. An action is either a C or a Q, but for the model the action always update the application state.
The action would call an API to get some data and propose to the results to the model, which would update the application state and render the view.
IMHO, CQRS is not a very useful pattern from an application architecture's perspective. Again it's semantics look interesting/familiar/attractive until you understand that mutation is the center of application architecture and computing.
Some guy I worked with at a client a couple of years ago was crazy about it until he tried to put it in practice...
Jean-Jacques Dubray
@jdubray
Jul 28 2017 14:00
I spent the last 20 years dissecting programming model semantics. I may have missed something, but the best thing I could up with is SAM.
Even things when you combine CQRS with DDD you get pretty much nowhere.
One should be careful when patterns have "gaps" or need other patterns to form a complete picture. So far I have not found gaps in SAM nor do I need additional semantics.
I can speak of it as if I didn't come up with it because really SAM is TLA+, without TLA+ I could have never come up with SAM. So it's not like I did a lot of work, I just dissected another programming model and found something that I felt was different enough and useful enough compared to all the other programming models I came across.
Victor Noël
@victornoel
Jul 28 2017 14:14
@jdubray do you think SAM has really meaning only in the context of UI apps, or is there some sense to use it for implementing services or other application that manipulate data but where the user interaction is not the hard part of the development?
Jean-Jacques Dubray
@jdubray
Jul 28 2017 14:21
it's a full Software Engineering pattern! it does not matter what kind of component subscribes to a state representation. If I was smart enough I'd create a programming language from it. SAM is everything OOP, FP, RP, FRP,... and countless patterns have tried to be.
I really urge anyone to objectively look at the programming model they are using and ask questions like "why would a pure function be the foundation of programming"? and just as objectively come up with an objective answer.
One should always pass the "cool factor" or the "simplistic factor", I understand what a function is therefore I understand what programming is.
Victor Noël
@victornoel
Jul 28 2017 14:28
I'm asking because now it's starting to be clear how it works with frontend applications, but it's not so clear now for non-frontend applications… especially because I'm used to Java for this kind of applications
Jean-Jacques Dubray
@jdubray
Jul 28 2017 14:29
You'd have to use a different kind of wiring to propagate the state representation to other components, in a headless way it maps to request response for instance (request -> action, state-representation -> response)
It's lineage to Paxos makes it incredibly powerful for distributed systems. Since you work on "the subject of software development for multi-agent systems" you might be very sensitive to that aspect.
Janne Siera
@jannesiera
Jul 28 2017 14:45
@jdubray Sorry, I didn't mean to shift the focus to CQRS or any programming pattern/paradigm. I was specifically refering to the "C(ommand)" part of CQRS as I am trying to wrap my head around what you just said about concurrency and actions. I wanted to verify that I was understanding you correctly.
Victor Noël
@victornoel
Jul 28 2017 14:49
@jdubray haha, you got me ;) altough I'm not familiar at all with formal development approaches to distributed computing, but yes, that's one aspect that interests me. Actually while discussing of SAM with some former researcher colleagues, we concluded that some of the programming models we were using are very similar to SAM :) it's not a surprise!
Jean-Jacques Dubray
@jdubray
Jul 28 2017 14:50
yes! I am certain that many people converged on similar ideas, but it's sophisticated enough that you need to lay it out precisely, it's not just a series of random thoughts.
@jannesiera it's ok, as I mentioned before a lot of programming model/patterns have merit but they tend to break down at scale. I don't experience that with SAM. The complexity of my applications remain constant, I believe it's because of this:
event -> action -> model -> state -> view -> event ...
                              |------> event -> (next) action -> ..
everything you do remains easy to reason about, unlike when you encapsulate code in a function or object/class
Victor Noël
@victornoel
Jul 28 2017 14:54
@jdubray yep, it was similar, but I'm pretty sure it was not exactly the same (pun intended) and it would be interesting to revisit it in the light of SAM!
Jean-Jacques Dubray
@jdubray
Jul 28 2017 15:12
I'd be happy to hear your feedback
(I am always interested in dissecting programming models)
Victor Noël
@victornoel
Jul 28 2017 15:19
for now, gogo vacations :) ciao, see you in a few weeks ;)
Jean-Jacques Dubray
@jdubray
Jul 28 2017 15:40
ah ah those French people!
Jean-Jacques Dubray
@jdubray
Jul 28 2017 16:49
Run 1000s of browser integration tests in parallel ⚡️
Crawl the web & automate screenshots
Write bots that require a real browser
Do pretty much everything you've used PhantomJS, NightmareJS or Selenium for before
Slađan Ristić
@sladiri
Jul 28 2017 16:55
nice, thanks
Janne Siera
@jannesiera
Jul 28 2017 17:01
bookmarked
thx :+1:
Jean-Jacques Dubray
@jdubray
Jul 28 2017 17:40
@jannesiera I'd like to add that when you use such decomposition:
event -> action -> model -> state -> view -> event ...
                              |------> event -> (next) action -> ..
  • refactoring tend to be easier and far less traumatic because you refactor one aspect at a time. There is rarely any overlap across these building blocks.
  • you can structure your team in specialties (e.g. model) or end-to-end scenarios (because the model or the state function are broken down as "acceptors" and "reactors")
Slađan Ristić
@sladiri
Jul 28 2017 21:26
To return to the "un-needed" control states of applications, I could easily eliminate those. That is, I could remove the code which computed these additional states, and just keep those relevant to the application in my blog example.