These are chat archives for jdubray/sam

26th
Jun 2017
burgenet
@burgenet
Jun 26 2017 11:55
For starters, this is my first time using Gitter (so please bare with me). Over the weekend I have been exploring as much as I can find regarding the SAM Design Pattern. One aspect that alludes me, is how to handle what I would term "widgets". For instance: I have an app with a top-level menu. From that menu I can click and open a window that contains a calculator. Also from that menu I can click and open another window that has a to-do list. For that matter, I can open any number of those windows. .... the OOP side of me says that I should encapsulate the functionality of being a "to-do list", "calculator", and "window" into a widget / wrapper of some sort. Does that work against/with the SAM Design? Meaning could I create an Object that encompasses a SAM based design for it's own internal functionality - encapsulating it's logic within itself? That way the "calculator" is an object that is designed with a SAM based pattern internally but the "to-do list", also designed similar, has no access to any of the "calculators" logic. ... or ... perhaps a different approach being: I create a SAM "controller" that encapsulates the logic for the "calculator" and then another one that encapsulates the logic for the "to-do list". Perhaps I then create a "shell object" that contains three items: the SAM Controller, the Model to be used with the attached controller, the element where I want the view attached (maybe that's an anti-pattern though?). .... Needless to say, I'm probably still stuck with one foot in the OOP world and peeking into the more functional world; but can anyone provide some thoughts about the encapsulation aspects or perhaps a link where this is discussed? Thanks.
Jean-Jacques Dubray
@jdubray
Jun 26 2017 13:41
It depends... sorry for that answer.
If the widgets are truly independent from each other you can create a SAM instance for each widget, perhaps with a parent instance as @burgenet mentioned.
In that case it would look a bit closer to OOP, but one of the goal of SAM and reactive systems is to depart quite a bit from OOP and centralize the application state rather than fragment it. In SAM the model is an Object, with a single method (present), that's as far as OOP you'll get.
The view components should be closer to functional HTML (V = f(M))
They can have some local state, but that state should have nothing to do with the application state (think something like config)
The examples you take (calculator, todo list...) look very disjoint, so that would be more like indenpendent SAM instances, with a mechanism that manages the widgets' position which could be SAM based or not. If it's SAM based it would be a parent SAM instance that manages the type, position and lifecycle of the widget (hydration/dehydration).
Jean-Jacques Dubray
@jdubray
Jun 26 2017 13:46
It's really important to let the OOP go and think in terms of individual building blocks:
  • view components (properties, events)
  • actions (events -> proposal)
  • model (proposal -> application state)
  • state (application state -> state representation as properties of the view components)
  • next-action-predicate (state representation -> next action)
The structure of these building blocks is not a class, OOP or even FP is the problem, not the solution.
I can of course implement SAM with any programming language, but the semantics of your programming model will not be OOP, FP, RP, FRP, ... they will be SAM based.
burgenet
@burgenet
Jun 26 2017 13:57
I'm going to process some of these responses; and maybe this evening I can start to work on a simple mock-up, using plain javascript, of my above scenario. I think I'm getting a better understanding - but it's very hard not to think of everything in terms of an "object"
Jean-Jacques Dubray
@jdubray
Jun 26 2017 13:58
one way to start is to think as components receiving properties and sending events
then you complete the loop from event to properties
event -> call action -> present propoal to model -> render state (new properties) -> update view component
Then centralize the entire application state in the Model
Did you take a look at that Sample? it's a complete one with a nodejs back-end. https://github.com/jdubray/startbootstrap-clean-blog
Jean-Jacques Dubray
@jdubray
Jun 26 2017 14:04
This has become my blue print for all projects, it works well for me.
It has a menu and multiple pages, including a basic router as well but I am not a big fan of routers.
burgenet
@burgenet
Jun 26 2017 14:07
@jdubray Yes. I have looked over the sample but I think I did not really understand some key aspects. I will retrace over the sample, with some of the above information and hope it sheds even more light.
Jean-Jacques Dubray
@jdubray
Jun 26 2017 14:08
Here is the most basic SAM implementation I could come up with (no view component), but you can start there, and add a bit of HTML around it:
let actions = {
countBy(step) {
    step = step || 1
    model.accept({incrementBy:step})
}
   }

   let model = {
    counter: 0,
      accept(proposal) {
          this.counter += (proposal.incrementBy>0) ? proposal.incrementBy : 0 
          state.render(this)
      }
   }

   let state = {
    render(model) {
          // render state representation 
        if (!this.nextAction(model)) { console.log(model.counter) }
    },

      nextAction(model) {
         return false 
      }
   }

   // start the reactive loop
   actions.countBy(2)
   actions.countBy(5)
burgenet
@burgenet
Jun 26 2017 15:36
What's your take on something along the following lines? https://codepen.io/bburge/pen/QgqYOw
Jean-Jacques Dubray
@jdubray
Jun 26 2017 15:45
perhaps SAM is the right way to structure a class :-)
You are close
So here for instance you should pass only name and completion properties, the view components should not have access to the entire model. it's the role of the state function to do that translation. In small apps or if you are sure you will never reuse these view components or you will never need to change them (as a theme) to reskin your app, then it's ok to pass the model to the view (components):
this.SAM.view.views.loading = (model)=>{
      return "Loading..." + model.raw.name + '('+(model.raw.completion || 0)+'%)';
    }
otherwise, I think that's pretty much it.
Jean-Jacques Dubray
@jdubray
Jun 26 2017 15:51
Again, I am not a big OOP fan, but that works.
burgenet
@burgenet
Jun 26 2017 15:51
Thanks. It's definitely been inspiring and I look forward to continuing to further grasp the functional aspects as well (if my OOP goggles can ever come off)
Jean-Jacques Dubray
@jdubray
Jun 26 2017 15:53
You should try to reimplement this sample starting from the basic reactive loop I posted above. It should be pretty easy. Then compare which one you like most.
In practice, I consider that part "wiring" of the pattern and there are many ways to wire the pattern, it's not important as long as the wiring works for you.
One big advantage of keep the wiring independent is that you can replace it with a dispatcher that calls your backend (for actions and/or model and/or state) at any time, with any combinations (some actions can run in the browser, others on the server). That's a big advantage of SAM, you never get lost.
burgenet
@burgenet
Jun 26 2017 16:33
I have a feeling I may have butchered this one slightly... https://codepen.io/bburge/pen/YQrMeV
Jean-Jacques Dubray
@jdubray
Jun 26 2017 17:23
it's clearer, I think you are getting there. You could also try to add this kind of code inside the next-action-predicate:
setTimeout(()=>{
        action.buildMore(model);
      },1000);
Jean-Jacques Dubray
@jdubray
Jun 26 2017 17:55
I want to emphasize that even though the code may look like a lot of overhead for a small sample like this, the SAM pattern keeps the complexity constant regardless of the size of the project, that's because the line of sight between event->properties remains fairly linear. You could still have a bit of overlap in the model (several acceptors could handle the proposal) but that's usually easy to resolve. That's why I often say that the many-to-many relationship between actions and acceptors is key to a healthy implementation and should never compromised, otherwise you'd start having to code a given acceptor with logic that belongs to the second one. That's when spaghetti code starts.
In a traditional event handler you'd have the actions/model/state/DOM manipulations code mashed up together and then you are dead.
You can only write spaghetti code in that case, you'd have to be superhuman not to.
devin ivy
@devinivy
Jun 26 2017 18:05

That's why I often say that the many-to-many relationship between actions and acceptors is key to a healthy implementation and should never compromised

extremely agree– this was my issue with "redux ducks"

Fred Daoud
@foxdonut
Jun 26 2017 18:13
@devinivy agree +1
Jean-Jacques Dubray
@jdubray
Jun 26 2017 18:16
:thumbsup:
In other words, with SAM you streamline the possible interferences to the minimum possible. It can still cause a few defects but in the model it's easy to reason about, no action or state/view logic. There is no interference in the action or state/view by design.
what is redux ducks?
Zach Dahl
@schtauffen
Jun 26 2017 18:27

that isn't a faux pas with redux ducks, you can export types for other ducks to listen to just fine I think

There will be some times when you want to export something other than an action creator. That's okay, too. The rules don't say that you can only export action creators. When that happens, you'll just have to enumerate the action creators that you want. Not a big deal.

Fred Daoud
@foxdonut
Jun 26 2017 18:27
@jdubray by the way, I loved the tweet you referenced: "Make everything easy to delete." It lead me to read Enduring CSS and it made a lot of sense to me -- it's the first CSS architecture pattern I actually liked and would consider using.
Jean-Jacques Dubray
@jdubray
Jun 26 2017 18:33
@foxdonut :+1:
@schtauffen @devinivy you gave me a headache... I am glad people don't build airplanes with a Redux architecture :-)