These are chat archives for jdubray/sam

6th
Feb 2016
Jean-Jacques Dubray
@jdubray
Feb 06 2016 00:09

I also wanted to emphasize another point that's very key to understanding SAM. This is coming directly from React.

What SAM does is that it forces the front-end developer to think in terms of model, no longer in terms of APIs. Given values in my model, how does the View look like. I don't care how the values got there, nor should I care. This is the paradigm shift that I got from React.

I am not saying this eliminates completely the need for request/response and interactions, but it tends to at least keep a balance between reactive and interactive. This is probably the hardest thing to get in React and SAM, you have to try it for yourself.

brucou
@brucou
Feb 06 2016 04:17
My understanding is growing with my reading which is a good thing, though I haven't reached the point where the advantages are obvious to me.
However, I wanted to contribute an updated diagram (yet another one I know)
alt
brucou
@brucou
Feb 06 2016 04:24
I am publishing this to show that there are three cycles in this graph, hence it should be possible to implement this flow in cycle.js with 3 drivers (DOM, Model, NextAction). Alternatively that can also be realized with standard RxJS with three subjects. I never actually wrote a program with cycle.js (@foxdonut maybe can help? ) but I can write it with standard RxJS. I can try to come up with something hopefully over the week-end.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 04:51
@brucou I am not comfortable with this diagram. As I mentioned:
when an action is triggered, passing it some data (e.g. user input),
data' = A(data) (the data may or may not be related to the model just yet, it is not model')
the output of the action is presented to the model
model' = model.present(data')
then the model is passed to the state to create the state representation (aka view)
view = S(model')
When there are automatic actions, the next-action-predicate invoke the automatic action after the state representation is created
view = S(model',nap)
the key to understand is that you cannot change that order, it comes directly from TLA+. I didn't come up with it, nor should someone feel that it can tweak it.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 04:59
If you want to see SAM in action in an algorithm (pure computation), here is an example based on computing factorial n (n!) http://www.ebpml.org/blog15/2015/04/star-based-component-model-with-tla-semantics/
The next-action-predicate is preponderant in algorithms, contrary to front-ends were there are very few automatic actions
PaulRogers909
@PaulRogers909
Feb 06 2016 09:24
This message was deleted
PaulRogers909
@PaulRogers909
Feb 06 2016 09:33
@jdubray Understandable that patterns become habits, multiline strings are allowed in ES6 Template strings.
       (`<p>Counter: ${model.counter} </p>
        <form onSubmit="return actions.start({});">
            <input type="submit" value="Start">
        </form>`);
brucou
@brucou
Feb 06 2016 09:51
@jdubray We are clear on that. Whatever you call it, present is called on the result of an action. Action gets its data from user input or from the result of the computation of the next action, and the next action is triggered by the display, i.e. comes right after the display. So I think we agree and that's what the diagrams shows hopefully.
Brian Haak
@avesus
Feb 06 2016 11:33
Lamport is Paxos design implementation author from MS Research. Cool!
Fred Daoud
@foxdonut
Feb 06 2016 13:24
@brucou here is the Cycle.js example: http://codepen.io/foxdonut/pen/XXPwRe
@brucou also I want to clarify something. You said "there are 3 cycles so there should be 3 drivers." This is incorrect. Drivers in Cycle.js are for side effects. If, for example, NextAction is a pure function, it doesn't need a driver.
brucou
@brucou
Feb 06 2016 15:18
I looked at your implementation in RxJS but I was looking for something that sticks more to my understanding of the architecture, and keeps the most of the code of @jdubray . In particular the next action part, which seems to be one the new things. Ideally the idea is to expose the formula that is mentioned above if that's possible
I mean the implementation works, I have no issue with that. I am trying to follow a form and see why that form would be better in general.
Fred Daoud
@foxdonut
Feb 06 2016 16:20
@brucou I agree with you. I need to think about the SAM pattern some more and how it would be implemented in code. The example pointed to in the InfoQ article, as mentioned, is not a good example IMHO. The functions are not pure functions and the code is messy. But, I am not criticizing @jdubray - he has made it clear that he is not a professional coder - so instead of complaining, my goal is to attempt to improve the code and see if it matches up with the theory that JJ explains in the article.
Fred Daoud
@foxdonut
Feb 06 2016 18:28
My attempt at improving the code example stalled at this: http://codepen.io/foxdonut/pen/GoYyPG?editors=1010
It doesn't quite work correctly, since Abort shows the aborted view but then the countdown clobbers the state.
I stopped here because either way, writing code in this manner is flawed.
The problem is how events get triggered from the view: <form onSubmit=\"JavaScript:actions.start({})
that makes the view need a reference to a global variable, and everything about pure functions falls apart from there.
Again, the theory sounds good, but to be valid, it seriously needs a solid code demonstration of the principles. Otherwise it remains, just a theory.
The plain JS approach is flawed IMHO. I don't like overcomplicated frameworks either. But, starting out with plain JS, as you write more and more code, you either end up with a mess, or you realize that you need some nice utilities that help organize your code. And guess what? You end up writing your own library. OR... just use one that someone else has already written.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 20:06
@foxdonut I am not quite sure I follow your argument where "wiring" is breaking the pattern. Components need to be wired to each other in some ways to be able to work together. The statement actions.start() is the equivalent of POST /start on a given host. Would you still complain if the form had a POST action?
Feel free to use any wiring scheme that works for you. I am not going to complain.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 20:16

Ok, I created several rooms to make sure we can discuss the arguments independently of each other. I agree it requires some serious examples to convey the benefits of the pattern. I am committed to do that. Here are the rooms I added:
sam-state-view: discuss V = S(M) how front-end developers write their code https://gitter.im/jdubray/sam-state-view
sam-apis: how back-end APIs fit within the pattern (actions and model) https://gitter.im/jdubray/sam-apis
sam-actions: A() https://gitter.im/jdubray/sam-actions
sam-model: M (M.present(), vm(), ...) https://gitter.im/jdubray/sam-model
sam-examples: general discussions about examples such as the rocket example https://gitter.im/jdubray/sam-examples

I'll leave nap alone for now as it is now essential to the pattern in the context of MVC.
I'll focus on sam-state-view today as this is kind of the main starting point of SAM.

Fred Daoud
@foxdonut
Feb 06 2016 20:23
This message was deleted
The SAM pattern is defined by this expression:
V = S( vm( M.present( A(data) ) ), nap(M))
There is no requirement whatsoever, for an explicit state machine. [...] The only constraint is that S, vm, A and nap are pure functions.
I know I'm repeating myself but my complaint is that the code example fails to meet this constraint. The functions are not pure functions. Everything is tied together with globals, and changes occur via mutations.
@jdubray I will stop complaining now since you have stated your intention to improve the code examples to respect the tenets of the article. I will wait and see how that pans out.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 20:27
Again, these things need to be "wired" to work, especially in a Reactive loop. Now I can wire the actions and the model with pub/sub, nothing wrong with that. The pattern is not prescriptive on how this expression is wired. From that perspective, any code sample I will produce will fail to meet these constraints. I am not quite sure I follow your argument. How would you wire the form (view) to the actions? How would you wire the actions to the model? and the model to the state? I can think of 15 different ways, they will all involve some coupling.
I found the expression to be a good summary of the pattern and clearly defining the intent behind each element. Clearly that expression is not how the pattern can be implemented.

If I write the action:

actions.launch = function(data, present) {
    data.launched = true ;
    present(data) ;
}

It's matches the constraints, I have broken nothing either way. The "action" is a pure function,

Jean-Jacques Dubray
@jdubray
Feb 06 2016 20:35
On the view side, I can write my form action any way I want, for instance, not sure I accomplished anything or one way breaks the pattern and the other one doesn't.
view.ready = function(model) {
    return (
            "<p>Counter:"+model.counter+"</p>\n\
            <form onSubmit=\"JavaScript:return actions.perform('start');\">\n\
                <input type=\"submit\" value=\"Start\">\n\
            </form>"
        ) ;

}
Fred Daoud
@foxdonut
Feb 06 2016 20:48
@jdubray the "action" is not a pure function! Your actions.launch function is not a pure function! A pure function 1) only depends on inputs, and returns the same result for same input; and 2) does not cause side effects. Your function does not return a result, and it causes side effects.
I'm sorry if I'm getting upset. Maybe I misunderstood the purpose of your article? Is it just a theoretical article, with no intention of a practical implementation?
Jean-Jacques Dubray
@jdubray
Feb 06 2016 20:56

We might have just a semantic issue here, I made it clear that I was following the TLA+ approach to defining actions/function:
data' = A(data)
In a "reactive loop" you do not "return anything, the data flow is unidirectional.
So if you prefer, I can write it:

actions.perform = function(a,input) {
    if (a === 'launch')    {
        var output = actions.launch(data) ;
        model.present(output) ;
    }
}

Not sure I accomplished anything different

It is not theoretical at all, I use it every day
I just tried to formalize in the article what I have been doing day in and day out, for the past few months.
Fred Daoud
@foxdonut
Feb 06 2016 20:57
On the other hand, the equivalent Cycle.js code that I wrote to demonstrate your launcher is based on pure functions. All side effects are isolated in a separate area of the code (drivers). You ask a good question: in a Reactive loop, how do we wire everything together? That is what Cycle.js, React/Redux, and others, solve.
@jdubray fair enough. I think there is a very big disconnect between the article and the code. What you have been coding day in and day out, is something, but it's not what you write about in your article. It's not pure functions. It's not reactive. It's not functional. It's mutative, imperative code.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:00
The problem that SAM solves is how to you factor the code within a reactive loop, across distributed tiers, something that React/Redux does not even start to address. Have you tried to write isomorphic code in React?
If you say so, I am not going to argue with it.
Fred Daoud
@foxdonut
Feb 06 2016 21:18
@jdubray I need to think about it some more. Look, I want to apologize for coming off as a jerk. That is not at all my intention. Think of it more along the lines of having a spirited, animated discussion over a beer at the local brewery.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:18
No, it's not that, I appreciate your arguments, but I can't convey everything in one code sample
Fred Daoud
@foxdonut
Feb 06 2016 21:19
Thank you. I wouldn't blame you if you did. I understand the challenge that you are facing.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:19
My intent was just to show the flow and a somewhat non trivial example that Redux cannot do easily.
I am looking at your code, it's very concise, and Cycle.js has some interesting features like showIf
Fred Daoud
@foxdonut
Feb 06 2016 21:20
I'll digest the ideas that you have put forward. The concepts ring true to me, which is why I am getting so worked up about it. I'm looking forward to subscribing to your channels and see how things pan out. Thank you for putting these ideas forward.
Cycle.js needs some conceptual understanding for sure, but indeed it can result in some fairly concise and elegant code.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:21
To be honest they ring true, I believe not because I came up with them, I literally came up with nothing, I slapped React and TLA+ together.
they ring true because of React and TLA+
Fred Daoud
@foxdonut
Feb 06 2016 21:22
Do you have some TLA+ reference reading material to recommend?
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:23
The problem with TLA+ is that it has it's own syntax and its formalism is derived from Mathematics. I tried many times to convinced Dr. Lamport to bring it to the level of programming languages, but so far he told me that he is working on other stuff and he is not interested in doing that
Fred Daoud
@foxdonut
Feb 06 2016 21:25
I see. I'll try to further understand SAM then. Merci, Jean-Jacques.
Vous ĂȘtes un gentleman.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:26
Here is a simple side-by-side example of TLA+ and state machines http://www.ebpml.org/blog2/index.php/2015/01/16/state-machines-and-computing
Now, this is the true theory behind SAM, or at least what I understand of it: http://research.microsoft.com/en-us/um/people/lamport/pubs/state-machine.pdf
I found this article to give me the perspective I was always missing to factor my code properly.
Fred Daoud
@foxdonut
Feb 06 2016 21:31
Nice, I'll be reading them, thanks! :thumbsup:
Jean-Jacques Dubray
@jdubray
Feb 06 2016 21:58
@foxdonut no worries, I am always open to discussions as long as the goal is to understand each other.
I have nothing to sell, SAM is just a pattern. I am just talking about my struggle to build OmniChannel apps, working with Front-End developers, and the solutions that I found that seem to help. If they help any one else, the better.
Fred Daoud
@foxdonut
Feb 06 2016 22:08
Completely agree @jdubray .
brucou
@brucou
Feb 06 2016 22:27
JJ here is my sample code inspired from your example
@jdubray , @foxdonut : feedback welcome
I tried to isolate the SAM functions from the data flow wiring as much as possible, and also put some annotations
brucou
@brucou
Feb 06 2016 22:33
ah yeah, there are a bunch of logging and what not to check the correct behaviour, the final code would be shorter.
brucou
@brucou
Feb 06 2016 22:47
JJ, some quick comments about this code
  1. There is no vm (as I think you mentionned before) in this particular example
Jean-Jacques Dubray
@jdubray
Feb 06 2016 22:48
wow ! that's a lot of work.
I don't want to sound negative, I am sure there is some room for futures, observable and promises, but when I look at your code, I feel that overly complicated. I am not disputing that these semantics solve some real problems, but we have to be careful in applying them to the proper problem.
brucou
@brucou
Feb 06 2016 22:50
  1. so far nap is not a pure function, but it could be made so, I put that on my list of improvement
  1. actions cannot be pure functions if they have side effects such as interfacing with the outside world through API
Jean-Jacques Dubray
@jdubray
Feb 06 2016 22:52
I think the key point that SAM introduces as you guys have noticed is the nap function, that is why I wanted to have an example with a meaningful next-action-predicate
brucou
@brucou
Feb 06 2016 22:52
  1. model.present is as expected directly modifying the model. It is also the only mechanism by which the model is modified which gives some nice guarantees about the correctness of the program
  1. state representation are indeed pure functions
Jean-Jacques Dubray
@jdubray
Feb 06 2016 22:53
It seems to me that proper state machine semantics work better to figure out the next action.
Here is the core of the problem in computing, as I was explaining to @foxdonut, computing is based on an approximation
brucou
@brucou
Feb 06 2016 22:54
  1. about terminology, I hear you, and I was insisting on that point before. You have a laxer definition of pure functions, and the formula you write is an illustrative one, not a mathematical one. I understand that, it is fine. It just looks so much like a mathematical one that you want it to be so.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 22:54
The approximation is that 99% of the times control states are unimportant
so when in reality, we write code as S1 -a-> S2 -b-> S3
What programming languages allow us to write is . -a-> . -b-> . (we omit the control states, because it would be highly inefficient to create states that serve no purposes)
brucou
@brucou
Feb 06 2016 22:54
and I don't seem to be able to make a numbered list on this damn chat
JJ, I read the article about the approximation of a program as a deterministic state machine, and I understand the point.
Stardrive Engineering
@HighOnDrive
Feb 06 2016 22:55
@brucou Switch to compose mode (cmd + /)
Jean-Jacques Dubray
@jdubray
Feb 06 2016 22:57
@brucou so, what I see in your code is that you no longer need obervables because the code knows the control state at all time, it can take the appropriate decision each time it gets control
brucou
@brucou
Feb 06 2016 22:58
@jdubray addressing your complexity comment, and about observables:
Jean-Jacques Dubray
@jdubray
Feb 06 2016 22:58
that's why your code looks overly complicated to me, because I believe it is an either-or, either you use the semantics of a state machine or you use observables, but both of them are redundant
brucou
@brucou
Feb 06 2016 22:58
You can remove the wiring data flow into a library that you just import, as a library user you just provide the S, vm, A etc. of your formula
if you look at that part, that's not complicated at all
I mean it is essentially the same code from your example almost verbatim
Stardrive Engineering
@HighOnDrive
Feb 06 2016 22:59
Hi all, I'm really enjoying the conversation and am intrigued by SAM. This resonates with me due to a pattern I discovered in my own work. Still reading up some more for a bit...
brucou
@brucou
Feb 06 2016 23:00
I mean of course that puts all closer to a kind of a framework but that would be a small one
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:01
Personally, I was chocked at how concise the Cycle.js implementation was, I like writing less code, as long as it is not mind bending to write it
brucou
@brucou
Feb 06 2016 23:01
Second point, the observable is addressign another concern and that makes them useful
Stardrive Engineering
@HighOnDrive
Feb 06 2016 23:01
Definitely want to follow up on this statement "either you use the semantics of a state machine or you use observables, but both of them are redundant"
brucou
@brucou
Feb 06 2016 23:02
It allows you for example to have actions calling asynchronous APIs which returm streams of values (event-sourcing?)
and use the observable operators to combine those data flows any which way you want
but anyways you don't have ot use it if you don't need it, actions can return simple object or strings or arrays or promises or whatever. Think about that as being in the library inside which you will never look to see the complexity, as you will just be a user of it
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:03
@HighOnDrive IMHO, and based on what I understand of TLA+ the next-action-predicate would make observables redundant because the nap tells you what to do at all time
With observables you have to reconstruct the knowledge of the control state, which people never do. They just assume they wrote the observable correctly and when the code triggers, then they are in the right (control) state to execute it.
brucou
@brucou
Feb 06 2016 23:05
@jdubray That's not true at all.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:05
It could not be more flawed... This is why AWS for instance is using TLA+ to debug its code.
brucou
@brucou
Feb 06 2016 23:05
You use observables anywhere you want for any concern you have in which it is the appropriate tool
I am not using it in my code to decide the next action
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:05
Well, that's how I see it, happy to be proven wrong but what TLA+ teaches you is that you can't tamper with the State-Action structure
brucou
@brucou
Feb 06 2016 23:06
In this example, the action 'decrement the counter in one second' is represented as an observable
that's the action not the nap
@brucou I was not talking about your code, I was talking in general observables are used as a poor-man's version of the next-action-predicate
brucou
@brucou
Feb 06 2016 23:07
who cares about how they are used in general? As I said, they are a tool who can help better than others to address some concerns.
in some situations
JJ, I insist on having concrete and specific discussions, not theoretical ones. Otherwise we'll be running incircles
specially given the disconnect in terminology and domain of expertise
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:13
sure, I am just commenting in general, it is clearly a digression
brucou
@brucou
Feb 06 2016 23:13
in DDD you try to get to an ubiquitous language with domain experts to further accurate understanding. We might get there through a chat but it is important that step by step we get closer to it.
we might NOT get there through a chat I mean, sorry
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:14
so in practice, and to be concrete, I don't see the value RxJs brings to SAM
brucou
@brucou
Feb 06 2016 23:14
This is like saying what is the value javascript brings to SAM
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:14
But I need to look at your code in more details, that's my first impression
I am about to finish another sample, using node.js, I'll publish it shortly
brucou
@brucou
Feb 06 2016 23:15
Just think of it as being part of the JS language
I mean RxJS is just the observer pattern, you don't need a library for that, you can do it as you did. What you did by the way is the continuation pattern.
In a lot of your functions, you end up calling another function, as the last line of that function, that is the continuation. Another pattern is the callback pattern
Who cares. These are syntatic details not semantic ones.
Some things are easier to use than others in some contexts, but all languages are turing-equivalent and there are a thousand ways to do the same thing
What I want you to look in the code is not the data flow wiring and RxJS details (you won't look in the C++ that implements the DOM right?) but that the semantics of SAM are implemented.
brucou
@brucou
Feb 06 2016 23:20
Ideally you would have a test suite, that does not even peak into an implementation and just checks an interface
Test suite could be, given (Sk; Ak.1, Ak.2, ...Ak.n), check that in the state Sk, the actions Ak.i, with i from 1 to n, are executed sequentially (if such are the semantics). given Sj, with j not k, check that none of the Ak.i are executed
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:35
Yes, I believe that's a big value of SAM, it makes the whole system a lot more testable. That being said, that comes from TLA+
@brucou you may call it the continuation pattern, but that's just a reactive loop. Nothing special about it.
brucou
@brucou
Feb 06 2016 23:49
schematically, continuation pattern -> f(a,g) = f(a) and what not then g() at the end, so g continues f.
Jean-Jacques Dubray
@jdubray
Feb 06 2016 23:49
I know :-) all, I am saying is that we don't have to call it that way in the context of a reactive loop...
brucou
@brucou
Feb 06 2016 23:49
it is similar to the callback pattern, except that in the callback pattern the callback can be called any number of times, and it allows asynchronous workflow
sure, just checking common terminology