Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Lee Owen
    @fleeboy
    Got it. Excellent stuff
    Jean-Jacques Dubray
    @jdubray
    Just to be clear there is no such as thing as the Action's model, an action is a pure function, it accepts a data set in, and produces a data set out. A model is "state" (in memory or persisted), once the action completes, there is nothing left.
    Daniel Neveux
    @dagatsoin

    Hi @jdubray First thx for bringing the SAM pattern. I had a (very) hard time to understand the principles because I found the approach too computer-science-high-level-of-abstraction for me. I am more used to the ducks and pizzas from the gang of four :)
    So, after weeks, I finally got it (at least I except to...) and it is really simple!!
    Now I have a question about how to reduce the increasing number of automatic actions.
    Let's take an exemple: in a MMORPG (I am building one) a player clicks on a vendor of the shop to buy something (I don't talk about model mutation for simplification here)

    1. player triggers openPanelAction --> state: shopPanelOpened
    2. nap triggers loadShopData --> state: loadingData
    3. loadShopData callback triggers handleShopData --> state: shopDataReceived
    4. nap triggers buildPanel --> state:panelBuilt
    5. nap triggers ...
    6. ...

    The problem here is that I have plenty of states which share the same context (open a panel) and are not used by the rest of the app. So I am looking for a way to encapsule this.

    You say that composition of actions is OK with C(data) = B(A(data)) but is it ok to do E(data) = C(B(data),A(data)) ? In other word is it allowed to trigger a sequence of actions in the same action?
    In my opinion yes because it is still one effect built with several independent effects sharing the same context. Isn't?

    If yes, can generator could simplify the number of states?

    Jean-Jacques Dubray
    @jdubray
    @dagatsoin thank you, all I do is very simple...
    So the core idea behind SAM is that the application state/model mutation follows a flow: propose/accept/learn and I agree what you describe is definitely a way to implement it, actually we were having a discussion about that very topic this morning in the main sam room.
    I would argue that what you are building, even though being logical leads to this kind of code:
    blob
    Daniel Neveux
    @dagatsoin
    ho
    I prefer pastas...
    Jean-Jacques Dubray
    @jdubray
    no offense, but the purpose of nap() is to deal with "automatic actions" that need to be triggered once you reach a particular state.
    pasta lack the "ball" structure
    The big question is really how do you deal with effects?
    And I would argue that you can actually run a query in an action and propose the results of the query to the model to mutate the application state.
    I do agree though that models are a bit weak in SAM, but the way you should probably implement them (specially when they are heavy like requiring a query) would be to have a local SAM instance that deals with the modal, from there you would trigger an action back to the parent SAM instance (something like submit, or with nap() if the action is automatic and requires the model to disappear).
    SAM instances are very light weight. So there is no real overhead in adding a SAM instance just for a modal.
    Jean-Jacques Dubray
    @jdubray
    You have two cases:
    • the panel is built after the query returned its results
    • the panel appears, the query then runs and update the state of the panel
    In the first case you don't need a separate instance and I would put the query (an effect) in the action, the action would present the results of the query, the model would update with:
    showPanel = true
    paneData = data
    and the State function would render the panel accordingly
    that way you have "ball" effect
    In case two, yes, you have to use nap() to trigger the query, but again, there is no need write some yarn code to keep track of the query state. I would only add some code for cleaning up the panel in case of timeout (the action never present the data).
    Would that work for you?
    In Multi Player games, SAM is particularly effective because all players can share the same application state and you never lose track of which action, from any player are possible, at a given point in time. The model acts as a critical section that processes only one action at a time.
    Jean-Jacques Dubray
    @jdubray
    Similarly, if there are any updates to the application state that need to be persisted, I would do it right there in the model rather than in nap(). Theoretically nap() is where it should happen, but IMHO, it creates too many opportunity for race conditions, i.e. the model is free to process a new action before the persistence can succeed or fail. IMHO, it's not worth it.
    Are you aware of the SAM-SAFE middleware? https://www.npmjs.com/package/sam-safe
    Daniel Neveux
    @dagatsoin
    Very interesting, indeed I am using two sam instances, one for server, one for the client (in game you need a local simulation of the world to avoid lag)
    My exemple was exagerate to make the point of the spagethi code if I use nap for everything.
    Jean-Jacques Dubray
    @jdubray
    Yes, again, in theory you should, but in practice I believe it better not too, you should use nap() only for something that needs to happen once you reach a particular state that no user would be able to trigger for instance. In any case, I would not use it at all for queries and updates.
    Let me know if you keep using SAM, I'd be more than happy to add you to the list!!
    Daniel Neveux
    @dagatsoin
    I will, indeed I have already implemented it from scratch with some modification to fits my need.
    The main change I made is for semantic. For exemple State is Status. And I keep State to represent a Model State. Which is simply a plain object that I wire to the view (react in my case but work for anything else) with MobxJS
    Daniel Neveux
    @dagatsoin
    Also, as I am in a game, all the action context logic (exemple: a player who heal another player) is a set of rule that the GameMasterService use to determine if the action is allowed or not. So some actions could be aborted without modified the model.
    Jean-Jacques Dubray
    @jdubray
    I would not underestimate the power of the State() function (including nap() that you are using)
    State() enables a complete decoupling of the view components from the application.
    Daniel Neveux
    @dagatsoin
    I keep using State() but it is a Singleton that I called App() because I am more confortable to use the word State for something like a bunch of variable representing the state of an object at a time.
    Jean-Jacques Dubray
    @jdubray
    The view components should know nothing about your application.
    It's ok, you can use any name that suits you.
    Please note that SAFE enables what I call "action hang back"
    Daniel Neveux
    @dagatsoin
    (looking at it)
    Jean-Jacques Dubray
    @jdubray
    Hang back is a bit more generic than cancel, it allows you to trigger as many action you want and let the first one win.
    of course you can cancel a long running action (like a query) by presenting a cancellation to the model
    Daniel Neveux
    @dagatsoin
    mmmh interesting, I have not implemented a fine way to cancel the action yet (appart from return; )
    Jean-Jacques Dubray
    @jdubray
    SAFE makes it generic, it keeps track of "steps" and assign unique ids to all action instances, so that for any given "step" only action can present data to the model
    It should be very helpful in your scenario
    Daniel Neveux
    @dagatsoin
    yes
    Jean-Jacques Dubray
    @jdubray
    can even make it fun for players to interact with each other without writing too much code
    Daniel Neveux
    @dagatsoin
    when ninjas grind a chest to be the first to get the treasureƧ
    Jean-Jacques Dubray
    @jdubray
    yes, excactly
    Daniel Neveux
    @dagatsoin
    :)
    I have also encapsulated the action to have a dev tool which keep traces of the triggered actions. This way the main loop is complety pure. "If action A is triggered with model state B then next model state will be R"
    Jean-Jacques Dubray
    @jdubray
    Yes, SAFE also implements "time travel", I agree that's generally a good thing.
    In your case, that is essential for debugging/testing
    Daniel Neveux
    @dagatsoin
    Yes, and SAM has implemented a very strong mental model. The decoupling is very clear.