by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Slađan Ristić
    @sladiri
    Hi, I am reading the "no-more-mvc-frameworks" article and Jean posted an example about an "increment" action and a model. I am trying to map this to CQRS, (but I am unsure if it even makes sense). Since the model checks the validity of the data, the action is not even a command in the CQRS sense but a mapping of user input?
    So if you used CQRS for this system, the model would would split its mutation in two steps:
    1. validate data + apply "increment" command
    2. mutate + generate "incremented" event
    Jean-Jacques Dubray
    @jdubray
    Hi, there is a reasonable alignment with Event Sourcing, it may even well be a missing link in the CQRS architecture. SAM decouples the invocation of back-end APIs from the view, therefore, there is no need/urge to map the view events to the commands. It may be more logical to map the action proposals to commands. You could as you mention in option two pick the event in the model, but I believe the proposal is more natural.
    @sladiri I would argue that we have been missing that clear distinction between model and everything else (CQRS being completely on the model side) and SAM (via TLA+ semantics) provide a much clearer isolation of the model business logic. All other approaches tend to mix action and state code with the model.
    Slađan Ristić
    @sladiri
    Thank you for your response!
    Marcus Feitoza
    @mfeitoza
    Hey guys I have one question in the above code:
    const model = {}
    
    // cat name space
    model.Cat = {}
    model.Cat.list = []
    
    // dog
    model.Dog = {}
    model.Dog.list = []
    
    model.present = (data) => {
        // only one present for both Cat and Dog
    }
    ///
    // OR I can have present for Cat and Dog?
    ///
    model.Cat.present = (data) => {
    }
    model.Dog.present = (data) => {
    }
    Jean-Jacques Dubray
    @jdubray
    There is no general rule, it's really about the "protocol" and the roles and responsibilities of Actions, Model and State. There is no problem modularizing the model as needed as long as Actions "present" proposals to the model and these proposals are serialized, unless you know what you are doing (there could still be parts of the model that could be updated concurrently, but IMHO, that's not a good thing.
    Marcus Feitoza
    @mfeitoza
    Thank you again JJ.
    Jean-Jacques Dubray
    @jdubray
    @mfeitoza What I meant by protocol was calling Actions->Model->State->View/Next Action in sequence. As long as you follow that "protocol" then everything should be fine.
    Marcus Feitoza
    @mfeitoza
    Fine, thank you.
    In this week I will develop little more complex app to dive into SAM
    Jean-Jacques Dubray
    @jdubray
    great! thank you for your interest.
    Marcus Feitoza
    @mfeitoza

    Modularizing the model is not clear for me, when you say

    There is no problem modularizing the model as needed as long as Actions "present" proposals to the model and these proposals are serialized

    because in SAM site says:

    The model contains all the application state and (logically) exposes a single method: present(data)

    I could do this?

    const model = {}
    model.present = (data) => {}
    
    // I could do, instead of having if's in present?
    model.presentNewtItem = (data) => {}
    model.presentEditItem = (data) => {}
    
    action.addNewItem = (data, present) => {
      present = present || model.presentNewItem;
      // all actions need
      present(data)
    }
    Jean-Jacques Dubray
    @jdubray
    You could, but personally I prefer a data interface to the model. It is important to decouple the actions from the model. The general idea behind TLA+ is that the actions propose the property values the model should take (imagine like a SQL UPDATE statement). Then the model decides if it's possible or not (accept or not, partially accept...). This decoupling is very important but not always possible to achieve. Sometimes the action needs to give a hint like when you need to perform an additive operation, you have to pass a proposal {incrementBy:1} since the action doesn't know the current value. The protocol forbids the action to query the model.
    Jean-Jacques Dubray
    @jdubray
    You can modularize the model by mounting some methods that will be called within present() Here is an example:
    https://github.com/jdubray/sam-samples/blob/master/vanilla-es6-boilerplate-project/html/components/menu.component.js
    For each component registered with the model, we iterate to call the update method(s):
    https://github.com/jdubray/sam-samples/blob/master/vanilla-es6-boilerplate-project/html/sam/model.js
    Marcus Feitoza
    @mfeitoza
    Thanks again JJ, I will learn about TLA+.
    Slađan Ristić
    @sladiri
    It seems that the model could use the state function to tell if some particular action data is valid to accept, doesn't it? I never saw an example doing this. The state function could have its second value as as hint for a user, which they might ignore.
    Jean-Jacques Dubray
    @jdubray
    sorry, I am not sure I understand your question. The model is solely responsible for mutating the application state.
    Slađan Ristić
    @sladiri
    No problem, I now saw the answer in one of your examples.
    I asked if the model can use the control state to decide how it mutates itself.
    Jean-Jacques Dubray
    @jdubray
    I would say in general no, again, that's the idea of separation of concern, it's better to make the control state evaluation redundant in that case. What I prefer doing is preventing the action to present its value based on the control state. When you look at SAFE, the state function returns the list of actions allowed in the current control state such that the model does not have to worry about that. The model assumes the action is allowed and simply makes the decision to accept or reject (or partially accept) the proposal.
    Milan Simonovic
    @mbsimonovic
    the discussion with @brucou seemed very important, too bad it ended on a bad note without reaching an understanding.

    One thing that comes up frequently is this concept called factoring, and sounds like it refers to code structure. Here're some examples:

    • "SAM recommends factoring the business logic underlying a graphical user interface along three building blocks: actions, model and state"
    • "The question is what is the proper factoring of code, you are not free to decide that, there are constrains."
    • "Bruno, there is only one factoring to computing, it's called TLA+, everything else that was built prior to that is an approximation"

    @jdubray could you please confirm this, or write your definition down?

    in these 3 examples it referrs to 3 different things: business logic, code, and computing. for the first two i have an idea what they could mean, but how to you factor computing?
    Milan Simonovic
    @mbsimonovic
    technically speaking, @brucou was right, SAM is not TLA+; SAM is a pattern, TLA+ is a language for writing formal specifications. If they were they same, you could write PAXOS spec in SAM
    but the PAL analogy I found very useful and illuminating, perhaps it should even go before TLA+ gets mentioned in the docs
    Milan Simonovic
    @mbsimonovic
    regarding the "S, vm, A and nap being pure functions with respect to the model", i take that means what is commonly understood as being pure - output is solely defined by inputs, there're no (visible) side-effects
    Milan Simonovic
    @mbsimonovic

    there was another phrase that caused some confusion - approximation, as in:

    • "the tuples (S1,A,S2) are another approximation, just like . -a-> . -b-> ."
    • "Classical State Machine semantics imply that the actions somehow connect two states.. This definition is somewhat of an approximation: it is not the action that decides the resulting state, it is the model" (from the docs http://sam.js.org/#sm)

    . -a-> . -b-> . looks like an action behavior (a sequence of actions), with states not being explicitly named, so that could mean it's an approximation of the full state-action behavior ?
    In the second example, perhaps the better phrase was misleading?

    Milan Simonovic
    @mbsimonovic
    I see why actions shouldn't update models, and I can kind of imagine why actions cannot decide the resulting state. This would be the case when the same action could lead to 2 or more different resulting states. For example, the glass is half-full, and the same action DRINK could lead to 2 different states: still HALF_FULL and another EMPTY, depending on the amount of water consumed.
    Milan Simonovic
    @mbsimonovic

    from https://dzone.com/articles/the-three-approximations-you-should-never-use-when:

    1. what constitutes a (programming, or computing?) step
    2. actions shouldn't decide the resulting state
    3. actions assign variables (to the model i suppose)

    these do not sound like what i would understand as approximations, at least not in the traditional sense (Earth is round, it's not but almost). what do these approximate then? perhaps a better word would be premise, or constraint, or even abstraction (explicit control states are abstracted away, there're only actions..)

    Milan Simonovic
    @mbsimonovic
    after going thru the docs and examples, i've got only one thing that bothers me. It's already been discussed as modularizing the model. Looking at the todo sample https://github.com/jdubray/sam-samples/blob/master/todomvc-app, model.present takes a data object, and has to decode what to do which boils down to model.crud https://github.com/jdubray/sam-samples/blob/master/todomvc-app/js/app.js#L134, which is one of the 5 things: switch to edit, complete item, Create/Update/Delete. It does have a benefit of giviving a simple and single interface to the actions (.present(data)), but on the other hand it's the only place in the pattern which seems to blatantly violate good programming practices (single responsibility, short methods, polimorphism over conditionals, ...). I understand this logic has to exist, but is there a better way to factor the code so it doesnt violate solid coding practices? I've looked into few samples but all seem to do the same thing (still have to go thru all of them so if i'm mistaken, please just point me out to the correct one). Please let's not discuss whether there's such a thing as best practice, I would just like to see how to factor the code so it does follow what's commonly considered good.
    Jean-Jacques Dubray
    @jdubray
    @mbsimonovic yes, I agree, I wish we could have gone to the bottom of this conversation in a more objective way. Since then I saw some videos where Dr. Lamport speaks about FSM and clearly TLA+ is not derived from Petri Nets.
    So yes, I confirmed what I said then. Basically computing is about defining "behaviors", a behavior being a succession of states, a state being a series of property values.
    S2 = f12(S1)
    S3 = f23(S2)
    ...
    The question is what is the correct way to define fij() for a given behavior. We can see that FSM define behaviors, no question about it but they are not general enough and in practice we all know that we cannot replace action-based programming languages by FSM except for some very constrained use cases.
    TLA+ "next-sate-relation" and the underlying formalism of Temporal Logic (operators like prime, always, existantial quantification) provides a framework, which I believe is widely applicable, to define behaviors.
    Programming languages tend to be "action-based" and are not concerned with the underlying behavior. It's all in the head of the developers. They only provide a structure to apply actions (be it functions or object methods). If you want to reason about the states and the next-state-relation, you can do it of course, but the language does not provide any particular structure for it and most developers never think of it that way.

    Of course:

    SAM is not TLA+

    I don't think I ever claimed that, I always said that SAM is my interpretation of TLA+ as a code structure, I welcome other interpretations.

    That being said,

    you could write PAXOS spec in SAM

    SAM is strangely aligned with Paxos, even though I had never heard of Paxos prior to coming up with SAM. So I feel there is somewhat of a connection between all three (TLA+, Paxos and SAM). But I agree, it could be fortuitous.

    but the PAL analogy I found very useful and illuminating

    I think it does, that's the first thing I talk about proposals/acceptors. And yes, that is the key difference between SAM and everything else I know, and yes again, that changed everything for me in terms of the way I code.

    Jean-Jacques Dubray
    @jdubray
    I'd rather not open the discussion on pure functions, I know what is the programming definition of a pure function, even Dr. Lamport has issues with them because they are not so "pure", we should really focus on whether a function changes the application state or not, that's why I think SAM actions work so well because you can now write a bunch of code that don't change the application state, and the code that actually changes the application state is reduced to a minimum and well isolated (in the programming sense too).

    output is solely defined by inputs,

    is not very interesting IMHO.

    Jean-Jacques Dubray
    @jdubray
    Classical State Machine semantics are an approximation in the sense that you already have made a mutation when you take an action, since you know the end state of the system.
    If you have a word other than approximation I'll take it, but it is an approximation in the sense that you get to a result that is close enough to the expected result but with caveats.
    Jean-Jacques Dubray
    @jdubray

    it's the only place in the pattern which seems to blatantly violate good programming practices

    I don't disagree but the many-to-many relationship between actions and acceptors is key to be successful with SAM. You can think of it as a publish/subscribe if you prefer, but it can be at the model property level. It is somewhat the keystone of the pattern because it ensures a true decoupling between actions and model. If there is a better way to achieve the same decoupling I'll take it.

    Milan Simonovic
    @mbsimonovic

    Classical State Machine semantics are an approximation in the sense that you already have made a mutation when you take an action, since you know the end state of the system.
    If you have a word other than approximation I'll take it, but it is an approximation in the sense that you get to a result that is close enough to the expected result but with caveats.

    i'm starting to get a feel for what you mean, but could you please expand your explanation? Or if i may: state machines are a model of computing, and as such, by the very definition, are an abstraction of what really happens (abstraction is the process of removing details, hopefully to better see the stuff that matters), or as you like to say they approximate what really happens.

    But I'm not getting where do you see this abstraction leak, perhaps an example would help, if you could just point me to, so you don't waste time writting again? Take a coffee machine for example, http://engineeronadisk.com/V2/book_PLC/engineeronadisk-307.gif, and suppose the model is amount_of_coins_inserted. From the default state idle there's 1 possible actions which is triggered when a coin is inserted. So if we do it the SAM way, this INSER_COIN action would propose a new value (1$) and the model would accept it, so we land at INSERTING_COINS state. Where's the approximation here? Why is knowing the end state a problem?

    Janne Siera
    @jannesiera
    @jdubray by classical state machine semantics, do you mean state machines where the update function is a lookup table?
    Jean-Jacques Dubray
    @jdubray
    @mbsimonovic @jannesiera there is a class of problems where there is an homomorphism between the actions and the resulting control state (i.e. a lookup table). Automata is such an example, all I am saying that is not true in general. It's generally not true in information systems. The graph of actions and states would tend to become very large. FSM do not scale in scope.
    _
    An alternative to FSM is to introduce a next-state-relation that decides what is the control state of the system.
    It does not mean that FSM are wrong, but it means they are not general enough, hence an approximation.
    Milan Simonovic
    @mbsimonovic

    it's the only place in the pattern which seems to blatantly violate good programming practices

    I don't disagree but the many-to-many relationship between actions and acceptors is key to be successful with SAM. You can think of it as a publish/subscribe if you prefer, but it can be at the model property level. It is somewhat the keystone of the pattern because it ensures a true decoupling between actions and model. If there is a better way to achieve the same decoupling I'll take it.

    well, this would be fairly easy to improve in a statically typed language like Java, with overloaded methods, for example:
    TodoItem.propose(SwitchToItemCommand), TodoItem.propose(DeleteCommand), TodoItem.propose(UpdateCommand), etc. In JavaScript it could be done via an event bus. But the exact mechanism is not that important, the question is does this increases coupling between actions and model. At the moment I don't see a problem, but perhaps this example with todo items is too trivial.

    @jdubray why do you keep mentioning FSMs? They are a type of state machines with a limited power (below pushdown automata, and two levels below Turing machines), so yes, they are not capable of expressing any computation, but state machines in general are.
    Jean-Jacques Dubray
    @jdubray
    I don't try to push my implementation of the pattern, I'd be happy if people come up with alternatives as long as they follow the semantics of the pattern.
    @mbsimonovic please provide a definition of state machines. In general people tend to point to FSM when they talk about state machines.
    Janne Siera
    @jannesiera
    About the terminology used: it might be interesting to know that tla is based on/inspired by abstract state machines. Abstract state machines is a computational model proposed as an alternative to the Turing machine interpretation of computation.

    as I mentioned above, it all boils down to the way you factor next-state relation:
    S2 = f12(S1)
    S3 = f23(S2)

    FSM being a particular care of ASM.