APIs, React.js, SOA, STAR

Introducing the SAM pattern as an alternative to MVC




This is a repost of my LinkedIn post.

I have been on a very interesting journey in the last few weeks as I was focusing on finding ways to lower the cost building OmniChannel Digital Assets.

These days, there are just too many combinations of form factors and platforms to support. This combinatory problem forces us to rethink the way we construct the “View”. There is simply no other way around it, one cannot create individual code bases for each form factor and platforms.

Over the last couple of years, frameworks like Angular and React have dominated the Web App construction market, but as we have seen recently with Angular2, the Google and Facebook teams are “still” searching for better ways to build UIs.

I’d like to formally introduce SAM, the State-Action-Model pattern as a replacement for the MVC pattern.

SAM is a derivation of both React.js and TLA+ concepts. SAM, as a pattern, can be expressed as a simple formula:

V = f ( M.present( A( data,M ) ) ) )

SAM stipulates that:

  • the View is a function of the Model
  • the Model is updated by presenting new values computed from Actions
  • Actions are pure functions

I prefer calling the View, State or State Representations, hence the SAM Pattern:

sam

There are a couple of key innovations that are worth noticing, the first one was brought by React.js, which showed us the value of expressing the View as a pure function of the Model.

The second one is more of a game changer because it fundamentally rethinks the role of the “controller”: Actions don’t “control” anything, they no longer decide of the resulting View, as it is the case in MVC, or worse, how to update the model, like in Redux. Actions are and must be pure functions:

data’ = A(data)

Each new set of values (data’) is “presented” to the Model, it is the Model that decides whether these values are acceptable or not and how they ought to be inserted into the model.  That approach is coming straight from TLA+. Once the model has been updated, the view is itself updated/rendered (React style).

SAM offers a strict separation between the View, the Model and the Business Logic (Actions). There is a bit of model-centric business logic in the model as well, but again, that business logic is completely decoupled from the Action logic.

The React.js team just came up recently with the Redux pattern, which is close to SAM, but exhibits an unnecessary and unwanted coupling between the actions and the model in the Reducer. The decoupling between the Model and the Action is essential and should never be compromised. (Please read also Edwin’s question in the comments below for more details).

An interesting side-effect of the pattern comes from the fact that its flow (trigger, present, update) does not interfere with APIs. API invocations can therefore be positioned naturally where they belong:

  • Actions invoke 3rd party APIs
  • The Model (exclusively) invokes its CRUD APIs (for instance something like HivePod.io)

For people who thinks in terms of Systems of Record and Systems of Engagement, SAM provides a natural articulation between them Actions sit in the SoE and the model’s operations at the SoR level.

If you want to see the pattern in action, here is a quick example I built last week-end: a simple about.me page. I started with an off the shelf HTML5 template, and simply created a functional wrapper, using plain vanilla JavaScript functions.

The underlying model is of course structured as a JSON object. The model itself is dynamically constructed  (in node.js): the list of blog posts is queried directly from the  feed of my WordPress blog and mounted in the model.

There is only one action in that example, the contact form. The view is not not supposed to display contacts (since they are private), but you can easily imagine how the Model gets updated from the function contact (name, email, message).

SAM does not require any framework. The factoring it provides, and the decoupling it achieves makes Frameworks like Angular2 and React.js entirely redundant. While working on SAM, I became convinced that MVC Frameworks were built simply to deal with the horrific coupling between the Controller and the View.  MVC is the problem.

Of course, SAM works just as well in the language of your choice: Objective-C, Java, C#, PHP… there is nothing specific to HTML or JSON or JavaScript.

In the next few weeks, I’ll come up with precise statistics and more code samples, illustrating the benefits of using SAM in the context of OmniChannel solutions.

You can read more about SAM on my blog:

5 Comments

  1. Adnan,

    the pattern does not specify the architecture, it simply specifies the semantics and the (reactive) flow. RxJS would be a perfect mechanism to implement the “present” method on the Model. You could equally implement it over HTTP, as long as you retain the semantics of the pattern.

    With respect to Cycle.js, again it’s pretty close, the View is a function of the model, actions are functions as well, however, it looks like the “present” semantic is absent, not that it could not be added, it would be rather simple to add that semantic.

    Now, you have to be really careful, because from a reactive programming model perspective, SAM is a variation of the traditional approach (http://cycle.js.org/observables.html#reactive-programming) where:

    “[the Model would be] fully responsible for managing its own state by reacting to external events. The [Action would be] unaware of the existence of the arrow originating from its network request event.”

    The SAM reactive loop is intentional: the State is aware of the possible actions (from an HATEOAS perspective) and these actions are aware as to where they need to present their results (the Model).

    Unfortunately the example that is chosen to (inc/dec counters) is not a good one because that action could be interpreted as an internal Model action (CRUD). In SAM terms, there is an action Increment that is defined as:
    x’ => x+ 1

    then x’ is presented to the model which would have some business logic that decides whether x’ is an acceptable value for x. Logically the “increment” action should not be known to the model, practically, unfortunately, this is a perfectly valid CRUD operation.

    Hope that’s clear, because this is a key point to understand the SAM pattern and the slight variant it brings to the reactive programming model.

  2. I guess the separation of Model and Control State is the key to understanding of the SAM pattern. My current understanding is that the Model contains the state of the program (as usual), whereas the Control State is solely derived from the Model, i.e. it contains the computed state. Is this a valid distinction? Moreover, the Control State determines which actions are valid for the given Control State (derived state) and which actions may be automatically triggered by the current reactive cycle. Does this mean the Control State represents our actual state machine? When the actual state transitions take place within the Model but the transition conditions are situated in the Control State, the abilities of the Model to accept/reject proposals by actions seems to be quite limited. What do I misunderstand?

    1. Apologies, I only saw your comment today. I see the Model as a representation of the system and the (Control) State as controlling the behavior of the system. The decoupling allows multiple behaviors for the same system. The control state for instance controls the automatic actions and the allowed actions in a given state. So yes the state transitions take place in the model, but the model is (generally) unaware of the states and transitions. The state is computed from the model current property values. The Model should only be concerned with the system integrity (like when a car cannot accept an RPM greater than say 6000 rpm). I feel that the separation Model/State is not just logical but extremely health (especially when you factor in that the (control) state is really the “state representation” of the system. It also decouples actions from state. IMHO, no offense to Carl Adam Petri, but it seems that it was a mistake to think that the state of a system is tied to the action you take, this is only an approximation, it’s often true, but creates too much problems in complex (information) systems.

Leave a Reply

Your email address will not be published. Required fields are marked *

− 2 = 3