APIs, React.js, STAR

SAM – A Functional approach to UI Construction



SAM is the “State-Action-Model” pattern, a new reactive pattern which seems to have interesting properties when building User Interfaces (Web or otherwise). SAM’s foundation is TLA+, so it can be used for many other things, but in this series of posts, I take a look at how we can use SAM to construct modern, OmniChannel User Interfaces.

The whole idea behind the pattern is to create a much simpler (when compared to MVC) feedback loop between the Model and the View:

sam

In essence, and in this context, SAM borrows many ideas from React.js, but without the ceremony that React comes with. The big game changer here is frameworks like bootstrap that allow us to decouple the “components” from the “page”. It would be harder to use SAM with a pure “page” formalism.

Let’s talk a bit about the ceremony introduced by React. I understand if I had to build Instagram, I would need that kind of framework, but that’s not for everyone. When you consider the burden of adopting and learning React, you may want to think twice before you burry your feet into it.

One of React’s original design goals was to be non invasive to the Web developer with familiar HTML-like extensions (via JSX):

 

But, a React component is not much more than a simple function call (var content = commentBox(data)).

That component-based functional connection between the State Representation and the Model would make React a perfectly fine way to implement SAM, if it were not for a couple of details:
– the way React allows you to push some of state (Model) in the view
– the lack of action semantics in the component model (it’s just not enough to say that React “is the view in MVC”)

Once you understand how SAM works, you realize how horrific React’s stateful architecture, I can’t think of a worse place to manage state than the view. The only “state” that should be known to a React component is its own configuration, with no relationship whatsoever to the model, that kind of code (stripped from Facebook’s documentation) is a complete anti-pattern:

 

What React got right (the reactive relationship between the Model and the View) they took it all back by enabling the spread of the model in the view. The view’s role should be to provide a representation of the model and enable the user to trigger actions, “intentionally”. Beyond that, there is no justification whatsoever, for a tighter relationship between the model and the components of the view.

Actions are the other big issue in React. The React team made it a complete after-thought, with no direct support for them in their component model. That massive oversight lead to a couple “patterns” (and associated libraries) Flux and most recently to Redux. Actions should be allowed to make third party API calls (any API call unrelated to the model) and the model, upon a new set of values, can decide how to persist itself or fetch more data (in particular via related API calls).

With SAM, the State Representation is a function of the Model to which Actions present values computed from a set of data that may or may not depend on the Model.

 
But, and this is a big “but”, the Model decides how and if it needs to update itself from the presented values. Actions have no decision power as to setting the state. In particular that means that when a user fires an intent to trigger an action, the action itself is purely functional, 150% functional, with again, no state whatsoever. In essence, SAM makes the React Architecture pretty much useless, 95% of React can be achieved with a simple JavaScript function. Ok, Ok… I also find the Virtual DOM amazing, but how many “apps” truly need it? Instagram, ok, I get it, Facebook, why not? SalesForce? SAP? your app? Nothing would prevent us to add a virtual DOM in the SAM implementation.

SAM as it stands is really simple, I don’t think one could find a simpler way to build Single Page Applications, yet it provides some of the best benefits of React + Redux without the weight of a framework.

So, how would a SAM-based application look like. Let’s take a simple example with my “about” page that I had originally constructed as a boring wordpress page and that is now a SPA running on Node.js. Note that the code shown here is strictly isomorphic and could run just as well in the browser when mounted properly. To write this code, I started from a raw HTML5 template, and created a series of JavaScript functions as part of a theme object:

As you can see, that kind of code is just plain vanilla JavaScript. What does the model look like?

 
What kind of benefit this pure separation between the model and the state representation brings? well, the model can be freely exposed as an API (yes, I know that looks a lot like Microformats), that means that when I join a team, their model can aggregate my information via a simple API call:

 

And, here is the architecture behind this code:

The blog section of the model is integrated via an API call (with a straight translation to JSON via xml2js) of the ebmpl.org wordpress feed. Pretty cool, hey? Ebpml.org itself is deployed on the Gliiph Platform and the About “page” is a Gliiph plugin, where the content of the About page is substituted with the content served from the SAM-based SPA.

Now, how do you “render” the model, you have different options, SAM does not prescribe a particular way, you can think in terms of pages if you’d like (as long as the model decides the next page to display, not the action), you can also think in terms of a single page applications with lots of if…then…else.

There is no need for an MVC framework. Yes, I know, as many readers have pointed out this is a pretty trivial case, but I am currently building an e-Commerce site for a client, with SAM, and there is simply no difficulty/constraints in applying the pattern, quite the contrary. There is also nothing specific about JavaScript and the exact same code could be written in Objective-C/Swift, Java or C#. The keys to applying the pattern correctly are:

  • 100% functional actions, which present values to the model
  • model drives 100% of the UI rendering
  • UI holds no state and triggers actions

If your application’s state machine is rather complex, making it a bit more difficult to decide what control state you’re in given a set of values from the model, I have created the STAR library. Again, the main difference with Redux is that it is not the action, like in traditional state machines, which decides of the resulting state, it is the model.

I’d be interested in your feedback. Since this seems reasonably new, do not hesitate to shoot at it.

8 Comments

  1. Your post is filled with terminology that gets in the way of actually explaining your ideas. Had to read over it at least twice to get the message.

    It’s really good to see you aren’t blindly smitten by a library just because of hype and backing by a very big company. It’s silly to like React just because people think React is awesome.

    I think majority of the blame here sits on React’s side for not completely clarifying its value add. It’s not easy because its value is more subtle, more pervasive and more important than you’d expect at first glance.

    Here’s the thing though: I don’t think you’re utilizing React properly.

    React’s job is to explicitly tie every view’s dependent data directly to it. If it were just the content, it wouldn’t be any different from any templating library. Every view, partial, subview … every possible state your UI gets into must be represented in React.

    What you have here is a templating system. Input a data structure and get a string that contains a template of what the UI should look like. Inject it into the DOM and you have your current UI. If you wire that up directly to data producers, you have dynamic templating.

    While that’s awesome, that’s not the problem React is trying to solve.

    Beyond templating is the problem that your UI gets into states and you need a reliable way to manage that state. Even simple interfaces get stateful.

    React’s job is to be the marshal of all the data that creates those states in your application, no matter their source. All the data that affects your UI is in one place.

    Here’s an example of something I made partially with React: http://wholesale.mizbeach.com
    (ps. it works offline too 😀 )

    All the list items are clickable. Some of the list items have images (a lot of the Samsung and Nokia, but there’s a couple Blackberry).

    How many different states can one list item get into?

    1. Basic Item
    2. Clicked Item (Pre-Image Check)
    3. Clicked Item (No Image)
    4. Clicked Item (Image – Not Downloaded)
    5. Clicked Item (Image – Downloaded)

    5 different states for a really simple list with very few properties.

    Note that the product name and price is already rendered. This isn’t about templating. This is about the state of your UI.

    React coordinates between the UI state and even third party modules, like Masonry, which I use to maintain the grid.

    Masonry subscribes to certain events React emits. The two work hand in hand like they are one element. Really though, it’s just that React marshals the data and coordinates every other aspect.

    To summarize: I think you’re simply using React as a templating engine. That’s trivial and not what it’s meant for. It’s to manage your UI state. It just so happens that it can do templating because templates are just your UI with base state.

    Ps.
    It’s a pity this is all I’ve written about React.js on my blog.

    1. Akamaozu,

      thank you so much for your reply. Looks like we have a lot of ideas in common (OOP, ES6…). That being said, yes, I agree, I have something close to a templating system, but it’s quite different from traditional templating frameworks and quite different from React too. The core of my argument is three-fold:
      – there is no room for “state” (as in model state/control state) in a React component (you seem to disagree) -> react components are/should be just functions, so why not using plain old JavaScript functions, what do you really gain by implementing a React component?
      – React’s Action model is a massive afterthought, Flux is a disaster, slight improvement from Redux, but not enough -> you need to make the actions 100% functional
      – A corollary of point #2, is that it’s particularly difficult to weave API calls properly in React

      SAM offers a pure functional view of UI construction (Model-View and Actions). That’s quite far from the common way of using React, and once you travel that path, you realize that React (or Angular) don’t offer much value. React has that interesting “instantaneity” feel (that you sample renders very well), but it’s not that practical to load a bunch of data just to get instantaneous responses. I guess my argument is that you are trading a slightly better UX for an architecture that’s a lot harder to code and maintain. That being said, I am not sure SAM would deliver such a crappy UX, but what SAM requires is that the Model be completely separate from the view.

      So I’ll stand firm on my opinion.

      1. Maybe I’m looking at it the wrong way, but I don’t believe that state “lives” in React.

        The only thing React needs to know about is data needed to render any piece of UI. That does constitute a lot of your data since the point of an interface is to present data and help users handle it, so it just seems that way incidentally. React isn’t interested in being the container of your data. It only happens to look that way incidentally.

        Your points about Flux, Redux or functional UI is lost on me. I have very little knowledge about terminology but I can tell you React can easily be used on its own. You don’t need to drink the rest of the ecosystem’s koolaid to get value from React.

        Your third point is interesting. I think it’s a lot of hard-wiring to pipe data down to the components that need it, granted. But it sounds like you’re trying to use React as the application itself, when it’s really just the view.

        Here’s how I used React.

        1. Pubsub as the application core.
        When the app boots up, it creates an app-wide pubsub.

        2. Components that talked between each other via pubsub.
        Components are pretty much functions that register under a namespace. They don’t really need the namespace, but I use it for logging so I know which component is responsible for what.

        The components emit / consume events via the pubsub. For example a component can emit save-to-disk, and as long as there’s a standard format the event is emitted / consumed, things will work out perfectly fine. We can have multiple components even act on it. For example, the logger can emit save-to-disk to persist the crash log if there’s no network connection to send it back to your server at the moment. It can then start listening for app-online, just in case it gains a network connection, where the callback basically is fetch-from-disk then send-to-server.

        Components are just functions that hook into the app-wide pubsub to do things.

        3. React is just another component. It emits events you can set up callbacks to handle changes by triggering the right React API. For example, you can set up a subscriber that’s basically this.

        product-data-updated -> React.setState( ‘products’, productData );

        The source could be an API directly, a component that manages it or a mixture of multiple components.

        In my trial I got data from localStorage as well as from an API and interwove them in React. I believe the components both emitted the same event. React didn’t know (and didn’t need to know) where the new data came from. It just did as expected.

        React emits an event when its done rendering the data, and my Masonry component is listening for it. Once React says it’s done, Masonry does its own part.

        React is not perfect, but it’s just a piece of your application. I don’t know about Flux or purely functional or Redux or whatever. All I can tell you with high confidence is a decently structured app doesn’t put React as its center-piece any more than you’d build an app around the template. It’s just another component.

  2. Interesting post, but honestly it could benefit from a substantially better explanation. All these diagrams can only go so far towards that goal.

    I appreciate the example but I find that some pieces are missing:

    – the present function : that is nonetheless the function you claim to be a substantial change. Quoting you : ‘But, and this is a big “but”, the Model decides how and if it needs to update itself from the presented values’. It would be nice to see such a case with a present function
    – the action function. The one that is supposed to be 150% functional.

    What I see is a series of html-generating helpers functions on a theme object, and a stateRepresentation function which generate html from a model and the functional helpers in theme. Just that is nothing new, and does not exemplify the difference brought about by your architecture.

    Most of the templating systems out there take an object and return html or something isomorphic to it (i.e. you can get html from it, and the other way around, through an inversible function, for instance html.toVdom(), vdom.toHTML() or what not).
    Among those : react (render function), ractive.js (toHTML function).

    Going forward, what would help is an example in which there is an UI with both transient state (state you can create fresh at initialization time) and persisted state (state you need to retrieve from a persisted data structure). Have two or more of what you call control states, which allow actions impacting both transient and persisted states., and a present function on the model detailing this impact.

    In the end, if you want to vulgarize your idea, you need to be more pedagogical about it, and end-to-end, complete, well-chosen examples are the best. Terminology is a barrier to understanding (model after all these years of MVC means different things to different people, etc.), examples help lower that barrier, by allowing to better infer the meaning associated to the words.

    My current understanding is that you just added a facade or extra layer between the actions and the model, which allows you to have functional actions, isolate side-effects in the model, and interface between actions and models with the present function. It might be a wrong understanding, in all cases, I don’t see what does that brings specifically.

  3. Like bruno already stated, your usage of terminology creates a certain barrier. Your ideas are intriguing, but I struggle to really “get” what you are writing. It would be benefical to have an end-to-end example of a simple, even trivial application implemented using the patterns you desribe. For instance if one were to create a self-incrementing counter that starts with 0 and increments the value by 1 each time the user clicks on it. I’d imagine the model would be a simple number, the action is a pure increment function (increment = n => n + 1), and the state/view is a pure function from number to html (stateView => model => ” + model + ”). How would one bind these functions to a UI? Specifically, how is the present function to be implemented?

  4. What you’re really saying is Components should be dumb / stateless. No one disagrees, in fact, this is a known best practice in the React community.

    It is how most of my React code looks like. I don’t see the point in inventing new libraries or TLAs (Three Letter Acronyms) to express this idea. React is an abstraction between your interaction logic and DOM / Native UI. It’s not the V in MVC.

    By separating models in to their own special construct and representing them on the client as data access objects, you’re walking right into the shared mutable state mess MVC frameworks like Angular created.

    Fair points about community Flux implementations but you should really look at Relay to see the amazing data integration patterns made possible through React.

    1. Zuhair,

      I have mixed feelings about React, on one hand, yes I find it’s architecture to be a major step forward (as explained in the context of SAM) on the other hand its implementation brings no particular value once you understand what it is trying to achieve, just incidental complexity. In IT things like this: “relay offers automatic data consistency, optimistic updates, and error handling” makes no sense at all.

      React was built by Facebook for Facebook, I understand why they need something like that, but hardly anyone else. Anyone who is serious about adopting React should watch this tutorial from Samer Buna, before they commit to it: https://www.youtube.com/watch?v=mubbsC-zIew

      >> separating models in to their own special construct and representing them on the client
      >> as data access objects, you’re walking right into the shared mutable state mess MVC frameworks like Angular created.

      I believe you are missing the point of SAM, in a true reactive loop no-one can call model.getState(), there is no shared mutable state in SAM. The sequence is:
      a/ actions compute the proposed values
      b/ model controls mutation
      c/ state renders view (State Representation) and execute next-action

      There is never a time where someone would call model.getState(), if you feel there are concurrency issues in your particular architecture, you can always implement the relation between State and Model, just like Store and Reducer in Redux. In the SAM’s Reactive loop no mutation can happen until a new action present new values, which happens well after the State representation is created.

Leave a Reply

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

+ 61 = 62