Why I No Longer Use MVC Frameworks
- Share
-
- |
Read later
Reading List
Web Development InfoQ Trends Report
Find out what technologies from the web development space you should keep an eye on this year. Be the innovator in your team and learn more about Vue.js, GraphQl and React. Read the report.
The worst part of my job these days is designing APIs for front-end developers. The conversation goes inevitably as:
Dev – So, this screen has data element x,y,z… could you please create an API with the response format {x: , y:, z: }
Me – Ok
I don’t even argue anymore. Projects end up with a gazillion APIs tied to screens that change often, which, by “design” require changes in the API and before you know it, you end up with lots of APIs and for each API many form factors and platform variants. Sam Newman has even started the process of institutionalizing that approach with the BFF pattern that suggests that it’s ok to develop specific APIs per type of device, platform and of course versions of your app. Daniel Jacobson explains that Netflix has been cornered to use a new qualifier for its “Experience APIs”: ephemeral. Sigh…
A couple of months ago, I started a journey to understand why we ended up here and what could be done about it, a journey that lead me to question the strongest dogma in application architecture, MVC, and where I touched the sheer power of reactive and functional programming, a journey focused on simplicity and scraping the bloat that our industry is so good at producing. I believe you might be interested in my findings.
The pattern behind every screen we use is MVC –Model-View-Controller. MVC was invented when there was no Web and software architectures were, at best, thick clients talking directly to a single database on primitive networks. And yet, decades later, MVC is still used, unabated, for building OmniChannel applications.
With the imminent release of Angular2, it might be a good time to re-evaluate the use of the MVC pattern and therefore the value MVC Frameworks bring to Application Architecture.
I first came across MVC in 1990 after NeXT released Interface Builder (It’s amazing to think that this piece of software is still relevant today). At the time, Interface Builder and MVC felt like a major step forward. In the late 90s the MVC pattern was adapted to work over HTTP (remember Struts?) and today MVC is, for all intents and purposes, the keystone of any application architecture.
Even React.js had to use an euphemism when they introduced a framework that, for once, seemed to depart significantly from the MVC dogma: “React is just the View in MVC”.
When I started to use React last year, I felt that there was something very different about it: you change a piece of data somewhere and, in an instant, without an explicit interaction between the view and the model, the entire UI changes (not just the values in fields and tables). That being said, I was just as quickly disappointed by React’s programming model, and apparently I was not alone. I share Andre Medeiros’ opinion:
React turned out to disappoint me in multiple ways, mainly through a poorly designed API which induces the programmer […] to mix multiple concerns in one component.
As a server-side API designer, I came to the conclusion that there was no particular good way to weave API calls into a React front-end, precisely because React focuses just on the view and has no controller in its programming model whatsoever.
Facebook, so far, has resisted fixing that gap at the framework level. The React team first introduced the Flux pattern, which was equally disappointing and these days, Dan Abramov promotes another pattern, Redux, which goes somewhat in the right direction but does not offer the proper factoring to connect APIs to the front-end as I will show below.
You would think that between GWT, Android SDK and Angular, Google engineers would have a strong view (pun intended) as to what could be the best Front-End Architecture but when you read some of the design considerations of Angular2, you don’t necessarily get this warm feeling that, even at Google, people know what they are doing:
Angular 1 wasn’t built around the concept of components. Instead, we’d attach controllers to various [elements] of the page with our custom logic. Scopes would be attached or flow through, based on how our custom directives encapsulated themselves (isolate scope, anyone?).
Does a component-based Angular2 look a lot simpler? Not quite. The core package of Angular 2 alone has 180 semantics, and the entire framework comes close to a cool 500 semantics, and that’s, on top of HTML5 and CSS3. Who has time to learn and master that kind of framework to build a Web app? What happens when Angular3 comes around?
After using React and seeing what was coming in Angular2, I felt depressed: these frameworks systematically force me to use the BFF “Screen Scraping” pattern where every server-side API matches the dataset of a screen, in and out.
That’s when I had my “to hell with it” moment. I’ll just build a Web app without React, without Angular, no MVC framework whatsoever, to see if I could find a better articulation between the View and the underlying APIs.
What I really liked about React was the relationship between the model and the view. The fact that React is not template based and that the view itself has no way to request data felt like a reasonable path to explore (you can only to pass data to the view).
When you look long enough, you realize that the sole purpose of React is to decompose the view in a series of (pure) functions and the JSX syntax:
<V params={M}/>
is nothing different than:
V = f( M )
For instance, the Website of one of the projects I am working on right now, Gliiph, is built with such a function:
(Click on the image to enlarge it)
fig 1. The function responsible for generating the HTML of the site’s Slider component
That function is fed from the model:
(Click on the image to enlarge it)
fig 2. The mode behind the sliders
When you realize that a plain old JavaScript function can do the job just fine, then your next question is why you would use React at all?
The virtual-dom? If you feel like you need one (and I am not sure many people do), there are options and I expect more will be developed.
GraphQL? Not really. Don’t be fooled by the argument that if Facebook uses it profusely, it must be good for you. GraphQL is nothing more than a declarative way to create a view-model. Being forced to shape the model to match the view is the problem, not the solution. How could the React (as in reactive) team possibly think it’s ok to request data with “Client-specified queries”:
GraphQL is unapologetically driven by the requirements of views and the front-end engineers that write them. […] A GraphQL query, on the other hand, returns exactly what a client asks for and no more.
What the GraphQL team seems to have missed is that behind the JSX syntax, the subtle change is that functions isolate the model from the view. Unlike templates or “queries written by front-end engineers”, functions do not require the model to fit the view.
When the view is created from a function (as opposed to a template or a query) you can transform the model as needed to best represent the view without adding artificial constraints on the shape of the model.
For instance, if the view displays a value v and a graphical indicator as to whether this value is great, good or bad, there is no reason to have the indicator’s value in your model: the function should simply compute the value of the indicator from the value v provided by the model.
Now, it’s not a great idea to directly embed these computations in the the view, but it is not difficult to make the view-model a pure function as well, and hence, there is no particular good reason to use GraphQL when you need an explicit view-model:
V = f( vm(M) )
As a veteran MDE practitioner, I can assure you that you are infinitely better off writing code than metadata, be it as a template or a complex query language like GraphQL.
This functional approach has several key benefits. First, just like React, it allows you to decompose your views into components. The natural interface they create allows you to “theme” your Web app or Website or render the view in different technologies (native for instance). The function implementations have the potential to enhance the way we implement responsive design as well.
I would not be surprised, for instance, if in the next few months, people start delivering HTML5 themes as component-based JavaScript functions. These days, that’s how I do all my Website projects, I pick up a template and immediately wrap it in JavaScript functions. I no longer use WordPress. I can get the best of HTML5 and CSS3 with pretty much the same level of effort (or less).
This approach also calls for a new kind of relationship between designers and developers. Anyone can write these JavaScript functions, especially the template designers. There is no “binding” syntax to learn, no JSX, no Angular template, just plain old JavaScript function.
Interestingly, from a reactive flow perspective, these functions can be deployed where it makes the most sense: on the server or on the client.
But most importantly, this approach allows the view to declare the minimum contract with the model and leaves the decision to the model as to what it the best way to bring this data to the view. Aspects like caching, lazy loading, orchestration, consistency are entirely under the control of the model. Unlike templates or GraphQL there is never a need to serve a direct request crafted from the view perspective.
Now that we have a way to decouple the model from the view, the next question is: how do you create a full application model from here? what would a “controller” look like? To answer that question, let’s go back to MVC.
Apple knows a thing or two about MVC since they “stole” the pattern from Xerox PARC in the early 80s and they have implemented it religiously since:

fig.3. the MVC Pattern
The core issue here is, as Andre Medeiros so eloquently puts it, that the MVC pattern is “interactive” (as opposed to Reactive). In traditional MVC, the action (controller) would call an update method on the model and upon success (or error) decide how to update the view. As he points out, it does not have to be that way, there is another equally valid, Reactive, path if you consider that actions should merely pass values to the model, regardless of the outcome, rather than deciding how the model should be updated.
The key question then becomes: how do you integrate actions in the reactive flow? If you want to understand a thing or two about Actions, you may want to take a look at TLA+. TLA stands for “Temporal Logic of Actions”, a formalism invented by Dr. Lamport, who got a Turing award for it. In TLA+, actions are pure functions:
data’ = A (data)
I really like the TLA+ prime notation because it reinforces the fact that functions are mere transformations on a given data set.
With that in mind, a reactive MVC would probably look like:
V = f( M.present( A(data) ) )
This expression stipulates that when an action is triggered, it computes a data set from a set of inputs (such as user inputs), that is presented to the model, which then decides whether and how to update itself. Once the update is complete, the view is rendered from the new model state. The reactive loop is closed. The way the model persists and retrieves its data is irrelevant to the reactive flow, and should certainly never, absolutely never, be “written by front-end engineers”. No apologies.
Actions, again, are pure functions, with no state and no side effect (with respect to the model, not counting logging for instance).
A Reactive MVC pattern is interesting because, except for the model (of course), everything else is a pure function. In all fairness, Redux implements that particular pattern, but with the unnecessary ceremony of React and a tiny bit of coupling between the model and the actions in the reducer. The interface between the actions and the model is pure message passing.
That being said, the Reactive MVC pattern, as it stands, is incomplete, it does not scale to real-world applications as Dan likes to say. Let’s take a simple example to illustrate why.
Let’s say we need to implement an application that controls a rocket launcher: once we start the countdown, the system will decrement the counter and when it reaches zero, pending all properties of the model being at nominal values, the launch of the rocket will be initiated.

This application has a simple state machine:

fig.4. the Rocket Launcher state machine
Both decrement and launch are “automatic” actions, it means that each time we enter (or re-enter) the counting state, the transition guards will be evaluated and if the counter value is greater than zero, the decrement action will be called upon and when the value is zero, the launch action will be called instead. An abort action can be undertaken at any point, which will transition the control system to the aborted state.
In MVC, that kind of logic would be implemented in the controller, perhaps triggered by a timer in the view.
This paragraph is very important, so please read carefully. We have seen that, in TLA+, the actions have no side effects and the resulting state is computed, once the model processed the action outputs and updated itself. That is a fundamental departure from the traditional state-machine semantics where the action specifies the resulting state, i.e. the resulting state is independent of the model. In TLA+, the actions that are enabled and therefore available to be triggered in the state representation (i.e. the view) are not linked directly to the action that triggered the state change. In other words, state machines should not be specified as tuples that connect two states (S1, A, S2) as they traditionally are, they are rather tuples of the form (Sk, Ak1, Ak2,…) that specify all the actions enabled, given a state Sk, with the resulting state being computed after an action has been applied to the system, and the model has processed the updates.
TLA+ semantics provides a superior way to conceptualize a system when you introduce a “state” object, separate from the actions and the view (which is merely a state representation).
The model in our example is as follows:
model = {
counter: ,
started: ,
aborted: ,
launched: }
The four (control) states of the system are associated to the following values of the model
ready = {counter: 10, started: false, aborted: false, launched: false }
counting = {counter: [0..10], started: true, aborted: false, launched: false }
launched = {counter: 0, started: true, aborted: false, launched: true}
aborted = {counter: [0..10], started: true, aborted: true, launched: false}
The model is specified by all the properties of the system and their potential values, while the state specifies the actions that are enabled, given a set of values. That kind of business logic must be implemented somewhere. We cannot expect the user could be trusted to know which actions are possible or not. There is simply no other way around it. Yet, that kind of business logic is difficult to write, debug and maintain, especially when you have no semantics available to describe it, such as in MVC.
Let’s write some code for our rocket launcher example. From a TLA+ perspective, the next-action predicate logically follows the rendering of the state. Once the current state has been represented, the next step is to execute the next-action predicate, which computes and executes the next action, if any, which in turn will present its data to the model which will initiate the rendering of a new state representation, and so on.
(Click on the image to enlarge it)
fig.5. the rocket launcher implementation
Note that in a client/server architecture we would need to use a protocol like WebSocket (or polling when WebSocket is not available) to render the state representation properly after an automatic action is triggered,
I have written a very thin, open source, library in Java and JavaScript that structures the state object with proper TLA+ semantics and provided samples that are using WebSocket, Polling and Queuing to implement the browser/server interactions. As you can see in the rocket launcher example, you should not feel obligated to use that library. The state implementation is relatively easy to code once you understand how to write it.
I believe that we have now all the elements to formally introduce a new pattern, as an alternative to MVC, the SAM pattern (State-Action-Model), a reactive, functional, pattern with its roots in React.js and TLA+.
The SAM pattern can be represented by the following expression:
V = S( vm( M.present( A(data) ) ), nap(M))
which stipulates that the view V of a system can be computed, after an action A has been applied, as a pure function of the model.
In SAM, A (actions), vm (view-model), nap (next-action predicate) and S (state representation) are and must all be pure functions. With SAM, what we commonly call the “state” (the values of the properties of the system) is entirely confined to the model and the logic that changes these values is not visible outside the model itself.
As a side note, the next-action predicate, nap() is a call-back invoked once the state representation has been created, and, on its way to be rendered to the user.

fig.6. the State-Action-Mode (SAM) Pattern
The pattern itself is independent of any protocol (and can be implemented without difficulty over HTTP) and any client/server topology.
SAM does not imply that you always have to use the semantics of a state machine to derive the content of the view. When actions are solely triggered from the view, the next-action predicate is a null function. It might be a good practice, though, to clearly surface the control states of the underlying state machine because the view might look different from one (control) state to another.
On the other hand, if your state machine involves automatic actions, neither your actions nor your model would be pure without a next-action predicate: either some actions will have to become stateful or the model will have to trigger actions which is not its role. Incidentally, and unintuitively, the state object does not hold any “state”, it is again a pure function which renders the view and computes the next-action predicate, both from the model property values.
The key benefit of this new pattern is that it clearly separates the CRUD operations from the Actions. The Model is responsible for its persistence which will be implemented with CRUD operations, not accessible from the view. In particular, the view will never be in the position to “fetch” data, the only things the view can do are to request the current state representation of the system and initiate a reactive flow by triggering actions.
Actions merely represent an authorized conduit to propose changes to the model. They, themselves, have no side effect (on the model). When necessary, actions may invoke 3rd party APIs (again, with no side effect to the model), for instance, a change of address action would want to call an address validation service and present to the model the address returned by that service.
This is how a “Change of Address” action, calling an address validation API would be implemented:
(Click on the image to enlarge it)
fig.7. the “Change of Address” implementation
The elements of the pattern, actions and models, can be composed liberally:
Function Composition
data’ = A(B(data))
Peer Composition (same data set presented to two models)
M1.present(data’)
M2.present(data’)
Parent-Child Composition (parent model controls data set presented to the child)
M1.present(data’,M2)
function present(data, child) {
// perform updates
…
// synch models
child.present(c(data))
}
Publish/Subscribe Composition
M1.on(“topic”, present )
M2.on(“topic”, present )
Or
M1.on(“data”, present )
M2.on(“data”, present )
For architects who thinks in terms of Systems or Record and Systems of Engagement, the pattern helps clarify the interface between these two layers (fig. 8) with the model being responsible all interactions with the systems of record.

fig 8. SAM Composition model
The entire pattern itself is composable and you could implement a SAM instance running in the browser to support a wizard-like behavior (e.g. a ToDo application) interacting with a SAM instance on the server:

fig. 9 SAM instance composition
Please note that the inner SAM instance is delivered as part of the state representation generated by the outer instance.
Session rehydration should occur prior to triggering the action (fig. 10). SAM enables an interesting composition, where the view could call a third party action providing a token and a call back pointing to a system action that will authorize and validate the call, before presenting the data to the model.

fig. 10 Session Management with SAM
From a CQRS perspective, the pattern does not make a particular distinction between Queries and Commands, though the underlying implementation needs to make that distinction. A search or query “action” is simply passing a set of parameters to the model. We can adopt a convention (e.g. the underscore prefix) to differentiate queries from commands, or we could use two distinct present methods on the model:
{ _name : ‘/^[a]$/i’ } // Names that start with A or a
{ _customerId: ‘123’ } // customer with id = 123
The model would perform the necessary operations to match the query, update its content and trigger the rendering of the view. A similar set of conventions could be used for creating, updating or deleting elements of the model. There a number of styles which can be implemented to pass the action outputs to the model (data set, events, actions…). There are pros and cons to each approach and in the end it might come to preferences. I favor the data set approach.
From an exception perspective, just like in React, it is expected that the model will hold the corresponding exception as property values (either presented by the action, or returned by a CRUD operation). These property values will be used while rendering the state representation to display the exception.
From a caching perspective, SAM offers a caching option at the state representation level. Intuitively, caching the results of these state representation functions should lead to a higher hit rate since we are now triggering the cache at the component/state level rather than the action/response level.
The reactive and functional structure of the pattern makes replay and unit testing a breeze.
The SAM pattern changes completely the paradigm of front-end architectures because, on the foundation of TLA+, the business logic can be clearly delineated into:
- Actions as pure functions
- CRUD operations in the model
- States which control automatic Actions
From my perspective as an API designer, the pattern pushes the responsibility of the design of APIs back to the server, with the smallest contract possible between the view and the model.
Actions, as pure functions, can be reused across models as long as a model accepts the corresponding output of the action. We can expect that libraries of actions, themes (state representations), and possibly models will flourish since they now be independently composed.
With SAM, microservices fit naturally behind the model. Frameworks like Hivepod.io can be plugged in, pretty much as-is, at that level.
Most importantly the pattern, like React, does not require any data binding or template.
Over time I expect that SAM will contribute to make the virtual-dom a permanent feature of the browser and new state representations will be directly processed via a dedicated API.
I found this journey to be transformative: decades of Object Orientation seem to be all but gone. I can no longer think in terms other than reactive or functional. The kinds of things I have been building with SAM and the speed at which I can build them has been are unprecedented. One more thing. I can now focus on designing APIs and Services that do not follow the screen scraping pattern.
I wanted to thank and acknowledge the people who kindly accepted to review this article: Prof. Jean Bezivin, Prof. Joëlle Coutaz, Braulio Diez, Adron Hall, Edwin Khodabackchian, Guillaume Laforge, Pedro Molina, Arnon Rotem-Gal-Oz.
About the Author
Jean-Jacques Dubray is the founder of xgen.io and gliiph. He has been building Service Oriented Architectures, and API platforms for the last 15 years. He is a former member of the research staff at HRL and earned his Ph.D. from the University of Provence (Luminy campus), home of the Prolog language. He is the inventor of the BOLT methodology.
Rate this Article
- Editor Review
- Chief Editor Action
Hello stranger!
You need to Register an InfoQ account or Login or login to post comments. But there's so much more behind being registered.Get the most out of the InfoQ experience.
Tell us what you think
Redux
by
Sam Havens
cycle.js
by
Daniel Campagnoli
Have you looked into that? Would you recommend it?
Re: cycle.js
by
Jean-Jacques Dubray
so first, SAM is a pattern and Cycle.js is a library. Nothing prevents you to use SAM to structure your Cycle.js code.
Second, Cycle.js seems to operate at the same level as React.js (i.e. the View). As such it takes a big short cut in the way you can express the logic in relation to the effects. SAM is based on the semantics of TLA+ and as such provide a foundation to cleanly separate three types of business logic: Action, Model and State. You just can't arbitrarily slice and dice business logic the way you want, otherwise you will not be able to achieve a reactive loops, there will be times where the actions need to call the model and/or the model needs to call some actions. Incidentally Cycle.js does not seem to have an explicit model, just streams, of which the logic and effects hangs off.
Last, I don't believe "everything" is a stream. Far from it. When you look at this Cycle.js example, you get a bit dizzy. You have to do that much thinking to increment/decrement a counter?
SAM pattern and building tools
by
Nachi Nachiappan
Re: SAM pattern and building tools
by
Jean-Jacques Dubray
I can also share some node.js code samples privately. The reason for that is that the code embeds copyrighted HTML5 templates what you would need to purchase if you want to use as is.
I really want to emphasize that SAM significantly lowers the barrier to build advanced Web apps such as this e-commerce Website.
Alternate path
by
Max Ward
I need more time to digest what you have here, but at least we identified the same problems.
Same old data problem...
by
Jim Nasby
It seems to me that at least some of the problems you're seeing in MVC are related to the problems I see in ORMs: the idea that data APIs should be transparent, and should follow your logical model.
In my experience, that's the opposite of what you want for a robust system. You want APIs that mirror the *physical* world. Shopping card application? The cart should be a self-contained object (that will ultimately reference many tables). User clicks the "Checkout" button? That should result in a single call to the database to get shipping options. User's finalizing the purchase? Again, a single call to the database with the shopping cart ID and shipping options, then the database creates the invoice records (again, most likely in multiple tables) before returning a complete invoice *object* back to the app.
With this kind of paradigm, you have a *real* API: the web code can do whatever it needs to for display. The database can do whatever it needs to for storage. Neither one needs to know what the other is doing.
I'm oversimplifying a bit here, and certainly there's data related operations that don't belong in the database (your rocket launch countdown is a good example). But in my experience almost every application developer thinks data storage should be a dumb thin layer on top of the filesystem, which creates chaos for everyone else that needs to do reporting or analysis on the data.
I think your SAM pattern is a big step forward, as it pushes state into the model. That at least allows for one place to focus on the API to backend storage (and API that is hopefully more sophisticated than CRUD).
Re: Alternate path
by
Jean-Jacques Dubray
yes, I believe we agree, the goal is/should be to decouple the way the UI is constructed and behaves from the underlying APIs that query/update the information model. When you shape your APIs to the view they become "ephemeral" to use Netflix's qualifier. Depending on which technology you use to build these ephemeral APIs, you are hosed. (not surprised they are aggressively moving to Node.js).
The argument I develop with SAM is that it's actually not that hard to decouple the UI construction and behavior from your APIs using a reactive/functional approach.
I'll publish more snippets over the week-end that show that you really don't need an MVC framework at all, because you no longer need to wire your APIs up to the view. That was the only value these frameworks provided, albeit it was the wrong thing to do.
The kids in the React team didn't even thought that was a problem, they were having too much fun with the virtual DOM, that is, until people started to build real things with React and then the question came back front and center. Flux was clearly not the answer, Redux, slightly better, but entangled the model with the actions because the pattern is using the wrong state machine semantics.
Re: Same old data problem...
by
Jean-Jacques Dubray
thank you for your comments, yes, after working with it for a couple of months and building an ecommerce website with it (will share some snippets over the week-end) I share your views that ultimately you want to achieve this:
the web code can do whatever it needs to for display. The database can do whatever it needs to for storage.
The Front-End developers will always push you for a CRUD like APIs (resource oriented?).
The beauty with SAM is that:
a) the "actions" become a conduit to the model, actions are by no means "controlling" how the data model updates, they just authorize for and prepare the data to be presented to the model
b) the functional construction of the view forces the front-end developer to think without any response in mind. V = f(M) is forcing the developer to reason holistically about the relationship between the View and the Model, far, far away from the Req/Resp treadmill.
Personally I prefer a data set/event-based interaction between the actions and the model because it gives all the power to people like you to decide how to best organize the information model, query and update it, perhaps you can chime in on that point. I was once a co-author of the SDO (Service Data Object) spec, to perhaps I am biased and there are better ways to deal with that question.
Robert "Uncle Bob" Martin - Architecture: The Lost Years
by
Dariusz Ostolski
www.youtube.com/watch?v=HhNIttd87xs
Which seems to be very related to your conclusions in the begging of the article (sorry it was TLDR)
gitter
by
Jean-Jacques Dubray
Re: gitter
by
Enguerrand Vidor
SAM Pattern
by
Hariharan S
It's really good to see this post addressing the problems in MVC.
I would love to look at some sample code / application developed using this pattern
Thanks
Hariharan
P.S - I was pleasantly surprised to look at this article :).
Re: cycle.js
by
Fred Daoud
That being said, I respectfully counter your "You have to do that much thinking to increment/decrement a counter in Cycle.js?" reaction with the same reaction to your code example (replicated here:codepen.io/foxdonut/pen/MKqXWj) -- you have to churn out that much code to implement a simple launcher?
There is just way too much "how" in your code. I find it so much more expressive of programmer intent to use MVI and event streams in Cycle.js: codepen.io/foxdonut/pen/XXPwRe
Respectfully.
Re: cycle.js
by
Jean-Jacques Dubray
the "state machine" is optional, I felt that was the best way to illustrate a "state" component. You'll notice that it is not present in the other samples.
The SAM pattern is defined by this expression:
V = S( vm( M.present( A(data) ) ), nap(M))
There is no requirement whatsoever, for an explicit state machine. You are free to write the S, vm, A, present and nap functions the way you want (including using cycle.js). The only constraint is that S, vm, A and nap are pure functions. The structure of the pattern is aligned with the semantics of TLA+, so even if you don't use an explicit state machine, you end up structuring your code in a way that's aligned with TLA+.
That being said, the semantics of cycle.js are incomplete from a TLA+ perspective. When that happens, people end up reifying lots of concepts behind streams and that does not look pretty.
I am certain we'll speak one day about being TLA+ complete, just like we talk about being Turing complete. TLA+ provides a strong foundation to computing that it is difficult to ignore, now mater how cool something looks in a given context.
Business Components as alternative as MVC
by
Javier Paniza
Framework Fatigue
by
Paul Rogers
May the SAM be with you....
Re: cycle.js
by
Paul Rogers
Re: Framework Fatigue
by
Jean-Jacques Dubray
Re: Redux
by
Jean-Jacques Dubray
Gitter
by
Jean-Jacques Dubray
I created several rooms to discuss the different aspects of the pattern and share some code samples.
sam-state-view: discuss V = S(M) how front-end developers write their code
sam-apis: how back-end APIs fit within the pattern (actions and model)
sam-actions: A()
sam-model: M (M.present(), vm(), ...)
sam-examples: general discussions about examples such as the rocket example
sam-archtiecture: general deployment / topology, composition discussions
Another examples using Node.js, Cycle.js and RxJs
by
Jean-Jacques Dubray
bitbucket.org/snippets/jdubray/jna7B
Some readers have also started creating samples using Cycle.js and RxJS, I will try to collect all the samples in that gitter room.
Easier to use React and GraphQL
by
Ashley Aitken
1. Sure React may just be equivalent to a pure function call but then it may be easier to use React / JSX to make components explicit, clear etc. It's more specific to the task at hand rather than a general Javscript function (if you know what I mean).
2. I'm still not convinced about the lack of a need for GraphQL. If all the front-end developers could just write Javascript functions and conceptualise what they were doing that would be great, but perhaps GraphQL is a simpler way to "write the functions."
I'm also not sure about getting away without a VirtualDOM but I haven't had time to follow that link you suggested.
Thanks again, and I hope my comments make sense.
Cheers,
Ashley.
Re: Easier to use React and GraphQL
by
Jean-Jacques Dubray
these are all great questions, and I can only encourage you to try the pattern for yourself.
They are actually fundamental questions because they have massive implications on the cost of building omnichannel solutions (which is the context in which this post was written).
I have started to share some of the code I write these days, to demonstrate that indeed you do not need React/Angular, GraphQL or even the VirtualDOM. There might be some apps where these technologies could add value, but on a day to day basis, I don't need any of them.
SAM allows the designer and front-end developer to have a much cleaner separation of concerns and consequently a much better working relationship. The semantics of Frameworks like React/JSX or Angular collide with the simplicity and elegance of HTML5/CSS3.
The reason why SAM changes everything is because the view is limited to be a "State Representation", there is never a need to go beyond "rendering the view", all the application logic stays in the SAM loop. That is why SAM is new and different. If there was ever a need to have a slightly more dynamic behavior, SAM's composition (fig 9) would again keep the application logic completely separate from the view.
Template technologies (including JSX, though in React you essentially create functions, so it depends how you use JSX, as a template or as a function) are simply the wrong technology because they severely limit your ability to create meaningful webparts from the model, while requiring the model to match the shape the template. Functions on the other hand deliver all the power of imperative language to render the view properly, without requesting the model to fit the view.
This is also why you don't need the virtual DOM, simply because you know exactly what will change in the view. Again, I don't dispute that there might be a few cases where the virtualDOM add value, but these cases are very limited. SAM gives you the ability to make decisions and optimizations from the model. Trying to optimize at the HTML element level is interesting from an engineering point-of-view, but again, unnecessary.
Last but not least, “Client-specified queries” are an absolute anti-pattern in Reactive architectures. The whole point of SAM is to achieve the best decoupling possible between the view and the way the model is formed (fig 7). By design in SAM, the view cannot request anything. It can only initiate reactive loops. When the loop ends, a new view is produced (figuratively, based on my point about the virtualDOM). Nothing else can happen in the view at all.
I can only encourage you to write some SAM-based code yourself, you will see how different it is and why you don't know need any of what React/Angular have to offer (again, in the context of building OmniChannel solutions).
Elm Architecture
by
Johannes Staffans
Do you see any key differences between SAM and the Elm architecture?
Re: Elm Architecture
by
Jean-Jacques Dubray
As André Staltz explains it, I believe there is a general agreement to "separate the logic from the effects". There is also a broad interest in our industry around reactive/functional programming models. React, Cycle.js, ... have showed that there is huge value in that approach.
With that in mind, if you construct a reactive loop such as Model Update View (or MVI), the assertion:
The logic of every Elm program will break up into three cleanly separated parts: model, update, view
That assertion is erroneous. You would be missing a couple of important parts:
- the logic that decides which state you are in so you can properly compute the view and enable the actions associated to the state
- the next action predicate
One can achieve a much better decoupling between the view and the model by introducing the concept of State to hold that kind of logic, otherwise you would have to fit it either in the view or in the model. The concept of "State" is critical to achieve that decoupling. The view then becomes a pure state representation, and hence a pure function of the model.
I didn't make up these semantics, they are coming directly from TLA+. TLA+ is used at Amazon to correct the most complex defects in AWS.
As a side note, some people like to call "control state" what I call state and they prefer using the word "state" to describe the content of the model. For me a model is just a set of property values with rules that decides whether some values are acceptable or not. The Model does not know anything about actions and state. Above the model, there are the (control) State and the Actions. Below is the usual CRUD to data stores. Above the (control) State and the Actions is/are the State Representation(s) (say in the REST sense, but not from a Resource-Oriented point of view).
So, it is not enough to break up the logic in just Model,Update,View. If people like André, Dan, Evan and others could engage in a meaningful conversation, about that very point, I believe our entire industry could make a major step forward.
None of what I am saying would break Elm, Cycle.js or Redux, an alignment with SAM would make them a lot stronger.
Re: Redux
by
Sam Havens
Also, I don't think Flux was a reaction to people building complicated apps with React - I think Flux architecture and the idea of the universal data flow predate React at Facebook. Not certain, but that is the story I heard.
Re: Redux
by
Jean-Jacques Dubray
you are referring to the discussion I had on the ngrx/store list?
The argument I developed there is pretty simple, I tried to boil it down to a simple example: let's say you trigger an action that increments a counter, all I suggest in SAM is that you factor the code in two steps:
a) an action (a pure function) hat given a dataset computes the proposed changes to the model
b) a method that mutates the model
The Redux reducer looks like this:
case INCREMENT:
return state + 1;
All I am saying, you need to write an action increment:
function increment(data) {
data.counter = data.counter || 0 ;
data.counter += 1 ;
return data ;
}
and then present the new value to the model which will choose to accept the proposed values:
model.present = function(data) {
if (data.counter !== undefined) {
// can have some validation rules that decides whether
// that value is acceptable or not
model.counter = data.counter ;
}
}
In SAM the actions and the model updates are strictly decoupled, unlike Redux which encourages people to create a big ball of mud, for no particular reason, other than Dan using a naive interpretation of state machine semantics.
With SAM, actions are external to the model and as such can be reused across models and even implemented by third parties. In Redux, actions are merely intents. The implementation of the action is in the model (reducer). That is wrong.
Please note that the way Actions are structured in SAM (expressed as a transformation) make them composable as a pipeline:
model.present(A(B(C(data))))
All I am suggesting is to move the action logic outside the reducer, the reducer keeping its role to mutate state. The same "reducer" logic would then work just as well with different actions (incrementByN).
We will not get out of MVC as long as the controller will update the state. Redux is a big step back.
About Flux, my comment was just regarding the fact that React is considered to be "just the view" and something was needed for M and C. Flux has some great ideas but completely missed the model part. Redux came around but completely missed the action parts. Both of them are however missing the "state".
For SAM, I am not claiming anything other than I applied battle tested, Turing award winning, decades old TLA+ semantics to front-end construction.
Thank you
by
Michael Terry
Re: Thank you
by
Jean-Jacques Dubray
Once you start coding that way you'll be amazed at what you can accomplish. Feel free to join us on Gitter, there are some great discussion going on.
I started to produce some public code samples as well to show how it compares to React/Redux and Angular/Rx, and why most people don't need either.
Several readers already came forward to create some samples with their favorite framework (cycle.js, vue.js,...). Cycle.js looks promising and shares some of the same goals: separating the logic from the effects.
Re: Thank you
by
Michael Terry
Native UI
by
Michael Donkhin
I believe, your approach could solve many of these problems.
However, I would like to ask you about how do you see implementation of SAM using native technologies (Android, WPF, Cocoa, etc.) and not WEB-based ones. You extensively use generating the View part using HTML templates, but in most of the native frameworks generating the view is either impossible or very expensive; and in those which do support such a thing (WPF data templates) the usage does not exactly align with proposed paradigm.
This is because MVC is misunderstood
by
Andreas Söderlund
Re: Native UI
by
Jean-Jacques Dubray
thank you for your comment. We fully agree, state is the problem (and React is one of the worst offenders)
Most of the frameworks we have to deal today spread the state among the components which results in endless bugs and virtual inability to introduce sane multitasking
and, yes, I also believe that SAM can completely change the game in Front-End construction, by bring back some sanity in that space. When you watch this video detailing the best way to build a React app, you understand very quickly that you are much better off staying away from it, and my guess is that it's true of Angular2 as well. It took me nearly 10 minutes on my mac to run npm install of the ngrx/core Item management sample (add/change/delete items to a list).
Just a few words about the work I have done in the mobile space, five years ago I built a model driven cross platform (iOS, Android) development platform called Canappi. So I know a thing or two about code generation. (the project is now open source, but not worth using, it's just too far behind).
As I mentioned in prior comments, one of the key benefits (and focus) of SAM is to clearly separate the logic from the effects as André Staltz puts it when he describes Cycle.js. That means that in theory (because I have not written some native code yet) the function V = f(M) can run in the native mobile client. You'd have to optimize how the reactive loop returns parts or all of the model. Not every application has the footprint of Facebook, so it's not such a burden do to return the whole model each time and let the view function pick up what it needs.
I don't know about the Swift programming model, but in Objective-C, that function would be equivalent to instantiating a view controller from the model (my preference would be to keep the model as parsed JSON rather than strongly typed classes):
MyViewControllerClass *vcInstance = [MyViewControllerClass newFromModel:model]
[self.navigationController pushViewController:vcInstance animated:YES];
The core of the implementation would be in the viewDidLoad method.
I do disagree with your statement:
the native frameworks generating the view is either impossible or very expensive
Again, I wrote Canappi, so I know a thing or two about code generation. In any case, you don't really need to "generate" anything, this is more parameterization of the view. You don't have to completely change the paradigm to start implementing SAM.
I used to be 100% native guy 3-5 years ago but because of the number of variants of form factors, I no longer think that Native is a viable model moving forward. I am doing some tests with Cordova + SAM now and so far so good.
Do you think that's a reasonable answer? Happy to review some code if you want to share a sample. Feel free to join us on Gitter.
Re: Thank you
by
Jean-Jacques Dubray
Re: This is because MVC is misunderstood
by
Jean-Jacques Dubray
I appreciate that a number of people are emotionally attached to MVC and the work of Prof. Reenskaug. I met him briefly in 1999 at OOPSLA.
With that in mind, I believe that if no one understands MVC after 40 years, I believe that if Google engineers have been flip-flopping on Front-End architecture for the good part of the last 15 years, it is because, MVC, in essence, does not exist, its semantics are so weak that it leads to code that no one can write, no one can debug and no one can maintain. MVC creates "run away" systems where the only answer to system construction is always to create more views, controllers and models.
I understand how much of a breakthrough MVC was in 1978, but we are in 2016, things have changed and taking the perspective of the user into account is no longer enough, you also need to include his/her friends, his/her smart watch and the uber driver approaching to pick him/her up when designing a "user" interface. SAM takes into account all these point of views.
Again, Apologies to Prof. Reenskaug, but MVC needs to go. There is no point in keep it, everyone understands that but there has never been a viable alternative. If SAM is not the answer, then another one will come.
String literals are our worst anemy
by
Remo Jansen
• Strings cannot be compressed by JS compressors so an application like that would be much heavier than one done with Virtual DOM
• Strings cannot be parsed by a compiler (like TypeScript) or the JS runtime so if we forget to close one of those </div> elements we will not have fun trying to find where is the error.
Re: String literals are our worst anemy
by
Jean-Jacques Dubray
I can choose to implement the pattern as I wish. I personally prefer a "raw" style of implementation, I tend to be see no particular value in all these frameworks. I would, again, as a personal preference, trade any day the ability for a framework to tell me I forgot to close a div to an npm install that takes 10 min to run on my Mac.
I am a server side guy, so compression means gzip/deflate not min.js.
Re: String literals are our worst anemy
by
Jean-Jacques Dubray
Re: SAM pattern and building tools
by
jiten oswal
Thanks
Re: Another examples using Node.js, Cycle.js and RxJs
by
jiten oswal
PS: I just added myself to 3 different rooms of yours related to SAM and information there looks hard to parse and catch all that's important :)
Re: Another examples using Node.js, Cycle.js and RxJs
by
Jean-Jacques Dubray
With respect to node.js there quite a few samples available:
- bitbucket.org/snippets/jdubray/jna7B/sam-sample...
- www.ebpml.org/blog15/2015/06/designing-a-reliab...
with the code available here:
bitbucket.org/jdubray/star-javascript/src/58062...
STAR is a small library that implements the pattern, but is not required for the implementing the pattern.
Virtual DOM & React Native
by
Rob Tweed
Re: Virtual DOM & React Native
by
Jean-Jacques Dubray
thank you for your comment. I would say it depends the type of application your are building. I didn't say you'll never need it. I understand it's value and respect the engineering behind it, but I would argue that today React is out-of-control (and Angular too). Facebook has taken a great idea and completely wrecked it. Is this really what it takes to write a Web app? One of my goals in the article was to reset the clock and show that you can build great web apps with raw JavaScript, HTML5 and CSS3. I am sorry that it came across as "you shall never use these frameworks again".
From what I can tell, I would say it's doable to use Cordova + SAM, I actually built a PoC last week for client. Looked great. When the "diff" is on the order of the content of a div element, I am not sure you need it. SAM creates the state representation at the end of the reactive loop (like React), so you are not touching the DOM several times. Is the virtual-dom working so well because of the diff algorithm? or because you apply all the changes at once?
Re: Virtual DOM & React Native
by
Rob Tweed
The thing I do like about what Facebook did with React Native was realising that mapping the virtual DOM to the native iOS UI components was possible, allowing a truly native app to be created just using JavaScript (as opposed to a hybrid app using Cordova). Otherwise we're on the same page! :-)
Re: Virtual DOM & React Native
by
Jean-Jacques Dubray
I don't dispute the fact that this is possible and it works well/better than Cordova, as I mentioned in an earlier comment, I built Canappi a few years back which generated iOS and Android code for up to 5 form factors, so I can imagine Facebook can do a much better job than myself.
That being said, what you need to consider is that developers and architects have a tendency to ignore state (as in SAM state, not Redux state with is SAM's model). The reason is because they are used to build monolithic architectures where the server-side code always acts as a safety net for whatever the client is trying do, this is a recipe for disaster when building composite/omnichannel applications where the APIs’ state machines cannot easily be aligned with the solution’s state machine, since they are built by different teams or even third parties.
That's why "State" needs to be explicit in the Front-End Architecture, and hence SAM, otherwise we'll be heading for a big big mess (I believe we already have). I agree with people that say State Machines are too heavy to write code and that's why SAM provides an interesting compromise, you can reason about State without having to result to a state machine systematically.
React or any MV patterns, especially the ones that start with MV has some inherent difficulty dealing with state because you can only infer the (control) state once the model has been fully mutated as a result to applying an action. Instead of "View" people should start adopting the language of "State Representation", that would change a lot of conversations.
I was reading this article this morning on Angular 1.5 and it shows everything that's currently wrong with Front-End architecture in 10 lines of code (databinding, templates, Google even thinks it's cool to attach the model to the controller? no... state):
// usage: <name-component></namecomponent>
var NameComponent = {
bindings: {
name: '=',
age: '='
},
controller: angular.noop, // or function () {} whatever
controllerAs: '$ctrl',
template: [
'<div>',
'Name: {{$ctrl.name}}
',
'Age: {{$ctrl.age}}
',
'</div>'
].join('')
};
angular
.module('app', [])
.component('nameComponent', NameComponent);
SAM, of course, is agnostic when it comes to how the state representation is rendered, so you can use React Native, Angular, or your own...
sigh...
</name-component>
GitHub Pages
by
Jean-Jacques Dubray
jdubray.github.io/sam/
Re: Easier to use React and GraphQL
by
Alex Hawkeye
The primary way GraphQL is used with React is through another library called Relay. Relay allows you to write small pieces of a GraphQL query called "fragments" next to your React components. Relay will fold together all fragments relevant in order to make the single GraphQL query network request to load the information necessary to render your views. Relay can do some pretty interesting things with this model as well, like serve you previously fetched data from cache while going to the server for newer information.
GraphQL plays nicely with a node micorservices architecture.You can also use Facebook dataloader to take advantage of caching. Works well with Redis github.com/facebook/dataloader#redis
Like it or not RGR( React GraphQL Relay) is here to stay. It is the future. Everything is moving client side. REST is dead. Front-end engineering is the future. Backend will be pretty basic relative to the complexity of the front-end. You'll just have full stack Java Script engineers. None of this back-end/front-end nonsense. Mainly comes down to economics. JS is just insanely cost effective. You don't have to believe me but it's happening just the same as JavaScript is the universal language of the future. medium.com/@mjackson/universal-javascript-47610... I remember, 3 years ago, when people laughed at the idea of JavaScript taking over the world. Now Node is 3.5 million strong with 100% annual growth and JavaScript is the most popular programming language in the world. Facebook has a lock on the web. It's too big to stop. Anything novel, they'll just acquire, hire the creator or steal.
You make some good points though and I like the idea of SAM but we need to get everyone on the same page.
The only difficult thing about using RGR is the initial setup. After that, it's so easy. Just plug-n-play. Long term maintainability is so easy. it's just hot swapping components. The more siloed everything is, the better. That's how the real world works and there is no reason it shouldn't be exactly the same on the web.
And lastly, you're a JavaScript expert and are able to conceptualize things that others with less experience aren't able to do just yet. A lot of startups like frameworks because a) they can't afford experts like you and b )it gets everyone ( regardless of experience ) on the same page. You may not like the massive influx of novice coders but the demand for programmers is just gnarly...and will only get gnarlier into the future.
Re: Easier to use React and GraphQL
by
Jean-Jacques Dubray
as a former co-author of the Service Data Object specification (SDO). I believe I understand GraphQL to a reasonable level. All that you are saying is correct, however, in the world I live the front-end very rarely talk to the database with no business logic in between. My world is also filled with all kinds of exceptions such as unavailable systems of record or failed transactions which require compensation.
When you live in that world GraphQL does not apply. Now I understand why Facebook built GraphQL and why it might work well for them, but I would refrain presenting it as a magic bullet. There has been countless products on the market that are GraphQL like (I tried to use MetaMatrix, Composite Software 15 years ago, participated in the SDO spec, ...). When your world is well formed they work like magic (with some edge cases around joins).
>> REST is dead.
you are saying that to please me ;-)
>> Front-end engineering is the future. Backend will be pretty basic
>> relative to the complexity of the front-end.
perhaps, our industry seems to love pendulum swings, personally I am agnostic, SAM unlike most of what React does is composable across tiers so I am totally agnostic to that argument and the composition patterns of SAM (say unlike Redux) allow you to be very smart about dispatching actions wherever they are... that is incredibly powerful.
>> JS is just insanely cost effective. You don't have to believe me but it's happening
>> just the same as JavaScript is the universal language of the future.
You don't have to convince me,I strongly believe that too.
>> you're a JavaScript expert and are able to conceptualize things that
>> others with less experience aren't able to do just yet.
Actually, quite far from it, I don't code for a living. I actually it is the other way around Frameworks stifle innovation because they require super advanced skills to work around their broken semantics and fake optimizations.
With SAM an ordinary developers can start writing very innovative and beautiful Web apps. SAM resets the clocks (sorry a TLA+ joke) on Frameworks and Front-End developer skills, not to mention bringing balance between designers, front-end and back-end developers.
So again, I don't discourage people using GraphQL below the model, sounds like a reasonable technology, but I would not present it as a magic bullet as you are doing, it is not applicable. I have heard so many time the story: "after a long and complex setup everything is easy"
SAM shows that everything can be easy: I can replace React.js+Redux+Thunks+Saga and have no urging need for GraphQL+Relay with a single line of code. Imagine that. I'll defend that claim any day.
Use RxJS
by
Tom Flaherty
Re: Use RxJS
by
Jean-Jacques Dubray
SAM's core value proposition is three-fold:
- it enables libraries of View components like never before because the View never contains a single line of business logic (what you would put in the view, you factor it in the State)
- it supports a precise articulation of APIs with respect to the Application business logic
- It is strictly aligned with the semantics of state machines, without requiring a state machine implementation, this means that you can now apply the 80-20 rule (80% of the time simple if-then-else would be enough to decide how to render the view, when you need to better understand the "current state" to decide what to do, the business logic is already factored in such a way that you can bring state machine semantics as needed)
There is no amount of Rx or Pub/Sub (aka wiring) that would give you these semantics. Generally, the Rx wiring lead you to do the wrong thing because you are forced to process actions without the ability to check the "current state".
Hope this is clear
Wiring and Semantics
by
Tom Flaherty
So then for the general UI components I recommend a decoupled approach with RxJS supplying just the right amount of wiring.
My specific business UI components which are named for their intent contain logic to drive presentation which can be based on semantics if they fit the business domain. I see no need for MVC or any other framework state semantics.
In my RxJS library the current state is published to you. The notion of a current state somewhere else is ill conceived and checking for it introduces unwanted scenarios even when guided by semantics.
To summarize:
1. The components are Views and REST interfaces that pub / sub changes.
2. The Model changes are the pub / sub payloads.
3. The Controller is replaced by a notification driven reactive approach.
Re: Wiring and Semantics
by
Jean-Jacques Dubray
>> the current state is published to you.
The current state of a system is computed from the model after it has accepted the proposed values from the intents/Actions.
In TLA+ the current state (aka control state) is computed from the model property value, I can't "start" a car when the battery is dead. I can issue that intent a million times, and the car will still not start. Sorry, it is as basic as that.
Wiring has nothing to do with this, Views are merely state representations. They do not stand on their own, they do not have interfaces and/or lifecycles. As soon as a view issues an action it's lifecycle ends and it is replaced by a new (logical) view at the end of the reactive loop. Otherwise your architecture is not reactive, it is interactive. There is no amount of Rx or Pub/Sub that will make it Reactive. Reactive means there is never a response (logically), even if physically it looks like a request/response for optimization purposes.
Feel free to continue the discussion on Gitter. gitter.im/jdubray/sam or read more about the pattern at: sam.js.org
Semantics and State Machine
by
Tom Flaherty
RxJS like all the ReactiveX streams is reactive that supports life cycles. Sending a "car won't start" or better yet a car status message when the "battery is dead" is easy.
As with any component we would implement a state machine as a set of RxJS subjects and attach them to our streams.
Upon reviewing SAM I see state machine semantics that fits an approach that your passionate about, so go with it.
At this point I need to break of the conversation to engage in some political activism.
Re: Semantics and State Machine
by
Jean-Jacques Dubray
It is actually TLA+, not SAM. I would never dare to say that SAM is even remotely close to be the foundation of computing.
>> MVC start prescribing approaches that lead to opinionated frameworks with too much ceremony
When you take a look at the architecture behind React+JSX+Redux+Thunks+Sagas+GraphQL+Play you realize that they slightly, almost imperceptibly ignored these semantics and before you know it you create "opinionated frameworks with too much ceremony" to correct what was simply a poor code factoring from the beginning. When the factoring is the problem, the framework is not the solution.
Let me take a simple example. A developer just asked the question on Gitter: is seneca.js a good fit for SAM? Seneca allows invoking actions based on some pattern matching technique. One would think cool, why not? That solves the problem everybody hates which is wiring the view to the problem actions. You have a number of ways to do that, including Rx. Wiring technologies come a dime a dozen (async or RPC).
How about we change our perspective on the problem? The problems stems from the fact that the View is perceived to be this statically defined object (especially in Angular). But in SAM V = S(M), the function S() acts as a mini code generator, the view components are "generated" on the fly (thank you React, that is such a paradigm shift). With SAM you can wire the view as needed. The State function knows everything about the current state, the allowed actions and can generate correctly wired View components.
You can take a look at the Theme functions in the TODO(notMVC) sample App
Looking at ReactiveX and subjects it looks awfully complicated for something that a mini code generators solves trivially.
V = S(M) (courtesy of React) is a major step forward for Software Engineering once you start measuring how different it is from templates + data bindings. Unfortunately for the Facebook team, they took again the wrong turn and made the React View "interactive" with GraphQL which is a particularly bad way to bind data to the View.
Re: Semantics and State Machine
by
Jean-Jacques Dubray
redux saga
by
Tudor Gergely
Re: redux saga
by
Jean-Jacques Dubray
Once the application state/model has mutated, you compute the next action, the concept of Saga (as imperative code) is very rigid and does not represent reality well (Sagas were created for trans-actions, not re-actions). State machines (SAM) provide a far easier way to compute the next action as a if (in state S) then A(...).
Dan has simply misunderstood the complexity of dealing with actions in relation to model mutations and he has conceded to patch his approach with Thunks on one side and Sagas on the other without measuring the implications on the overall architecture. When you combine that with the fact the Reducer:
- does not scale since you have to mutate the entire application state
- cannot be isomorphically run on the server or client
- cannot invoke APIs (CRUD or 3rd Parties like SAM)
I am not quite sure why you would consider using Redux at all. If you want to use React but you are not sold on the React nebula (Redus, Sagas, Thunks, GraphQL, Relay...) , SAM offers a far simpler, isomorphic, architecture.
Dan is focused on one thing: tools (Time Travel, Hot Reloading) not on architecting front-end/back-end. We have Time Travel with SAM: github.com/sam-js/sam-devtools
Feel free to join us on gitter: gitter.im/jdubray/sam
Re: Same old data problem...
by
Arturo Hernandez
Great Article
by
Othon Reyes Sanchez
Re: Great Article
by
Jean-Jacques Dubray
Here is the pattern's home: sam.js.org which contains links to many samples produced by the community.
One of the most recent samples is an AWS Lambda implementation with a dynamoDB session manager: github.com/jdubray/sam-samples/tree/master/crud...
sam as an isomorphic architecture
by
stefan houtzager
Javascript for developing node was just a poor choice. Read here bostinno.streetwise.co/2011/01/31/node-js-inter... why Ryan Dahl choose javascript. What you can trust (and it is proven to be very reliable) is the actor-based concurrency model. Here about the model diffs: joearms.github.io/2013/04/02/Red-and-Green-Call...
isomorpic
by
stefan houtzager
To use javascript for such a thing was just a poor choice.
Read here bostinno.streetwise.co/2011/01/31/node-js-inter... why Ryan Dahl choose javascript to develop node in.
What you *can* trust (and the model *is* proven to be very reliable) is the actor-based concurrency model. Here about the model diffs: joearms.github.io/2013/04/02/Red-and-Green-Call....
Re: isomorpic
by
Jean-Jacques Dubray
I appreciate your insistence on making your point, you are entitled to your opinions. Node being good for I/O and nothing else is a well known fact. I am pretty sure every InfoQ reader knows about it. I would argue, however, that SAM is Node's best friend since instead of writing the business logic in one big blob, SAM encourages people to use three buckets (Actions, Model and State) which helps a bit. Perhaps we could ask Netflix what they think about Node.js?
I don't know any other approach where Isomorphism between Server and Client is so seamless (SAM+Node). You can move as little as a single action, to any combination of actions and model, model and state, ... after writing all you code... on the client. I have even shown that the same code runs unchanged ... on AWS lambda.
SAM being a patten, I certainly encourage people using it everywhere they want and do not seeing tied to any given technology. What is clear though is that FRP is not going to crack the front-end/back-end architecture. We have confounded assignments with mutation for decades. Trying to put a big box (function, actor,...) around some poorly written code is not going to solve that problem. It is only by implementing mutation correctly that we will solve that problem. SAM is based on TLA+ / Paxos, I certainly encourage everyone to learn more about them and make mutation a first class concept of their programming model. Immutability is the wrong way to think about... mutation.
PS: I am at t=26min of the presentation you referenced and I have learned nothing new/of value. Just the usual stock photography and trivial code samples, so I'll stop here.
ERP en 'SAM'?
by
Nicolas HUGODOT
Nous sommes une petite équipe qui essayons de créer un ERP Web communautaire, mix de airbnb Uber et Odoo Facebook etc.
Serveur en Python car aucun framework FP n'est encore aussi mur que Django par exemple, mais j'ai encore de gros doutes quant au front: Angular 2, Elm qui m'a séduit et que nous investigons, ou... Pur JS grâce à l'approche SAM ? Regardez Facebook et Odoo, à votre avis ces deux UX et Ui sont elles faisables, avec le maximum de productivité en création puis évolution maintenance, en Elm ou SAM JS ?
Un très très grand merci pour cet article passionnant (mes ingénieurs n'ont pas encore tout décortiqué) et vos conseils.
Re: isomorpic
by
stefan houtzager
How entitled are you yourself on selling your isomorphic ideas? I think you try to sell your ideas very aggressively, whereever you can. A bit of googling reveals discussions in at least elm and react groups (more will be simple to find). F.e. your comments in github.com/reactjs/redux/issues/1528 are remarkable. They are often not very considerate; you're sitting high on your horse and you hide behind your jargon.
The goal of my reaction is a warning to others reading your articles to be very carefull. Some of your ideas might not be such a good idea to realize. Waving with a netflix article is not convincing. I'd rather trust my own ears and senses than the big names and jargon you hide behind "TLA+ ! Lamport! Do you think you're smarter than Lamport?". You can easy find articles from / about companies switching from node to f.e. go. For the rest the links I already sent are convincing, to me at least. To me you're a friars latern. Interesting lights leading nowhere.
Re: ERP en 'SAM'?
by
Jean-Jacques Dubray
merci pour le feedback, n'hesitez pas a nous rejoindre sur Gitter pour continuer la discussion.
J'ai développé tres tot une allergie aux frameworks, mais SAM marche quand meme tres bien avec Angular2 ou meme Elm. SAM exprime simplement qu'il ne faut pas confondre "assignments" avec "mutation" et que par consequent il vaut mieux partitionner sa logique metier en trois "buckets": Actions, Model et State.
Les UX d'Odoo ou Facebook sont totalement faisables avec SAM. En fait SAM permet d'utiliser toutes les possibilités d'HTML5/CSS3 sans la lourdeur des frameworks qui tendent a les limiter.
Si vous avez des questions specifiques n'hesitez, toujours heureux d'y repondre.
JJ-
Re: Thank you
by
Wing Cheng
I am busy rereading sam.js.org and Leslie Lamport's book 'Specifying Systems' in past 2 weeks. You remind me what I have studied in hardware. The circuits don't work as design/desire if the math is wrong.
It is different in programming UIs; usually, they mostly works as desire but leave some difficult to fix and highly coupled mixed concepts in the system.
Plan-Tree execution.
by
Richard Green
Re: Plan-Tree execution.
by
Jean-Jacques Dubray
I'd be happy if you share the links. You can also join our community on Gitter: gitter.im/jdubray/sam
JJ-
Re: cycle.js
by
luca mezzalira
sorry if I correct your message, cycle can be written in many different ways, one of this is with MVI (model - view - intent).
If you check in the official examples and in the documentation you can see how the pattern works.
it's a unidirectional pattern where model, view and intent are pure functions that are linked together by observables.
With Cycle you can also work with a state management like onionify that leverage the concept of fractal architecture (github.com/staltz/cycle-onionify)
Last but not least, you can also create a plugin architecture using MVI for the components and the grid driver as communication bus: medium.com/@domagojk/creating-a-scalable-javasc...
Re: cycle.js
by
Jean-Jacques Dubray
thank you for the pointers, I am glad that since this article was published, Andre finally came to his senses and drove Cycle.js towards a single-state-tree architecture (though an "onion" may not be the best moniker to label this major breakthrough). When you look at the way people build "large apps" with Cycle.js, that doesn't sound very convincing. The ToDo app diagram shows an overly complicated, and dedicated flow that contrasts quite a bit with the electricity metaphor that the author is trying to convey.
Since I wrote this article I realized three things that I'd like to share:
1/ you need to reason clearly about the programming model, the wiring and the architecture of your system, Frameworks tend to "sell" you a bundle that is not optimal. I don't sell anything, SAM is just a programming model that you can use with any framework, any wiring and any architecture. However, I would greatly encourage people to think thoroughly their choices.
2/ SAM and Functional Reactive Programming (Elm/Redux/Onionized-cycle) overlay quite well. SAM simply states that:
- what redux calls actions or elm calls messages are events
- the "reducer" or "update" function need to be factored in three buckets: actions, model and state. There are real benefits behind that factoring
3/ last but not least, we have been writing software for decades using 3 approximations
- actions can change the application state
- assignments are equivalent to mutation (I assign therefore I mutate)
- there is no need to define clearly what is a "programming step", so when we write a = b+c, we don't need to ask if that's the right programming step or if, for instance, we need to distinguish: read b,c ; compute b+c; assign a with b+c;
Using these approximations is not wrong, but they are nevertheless approximations which do not apply to modern distributed systems.
SAM addresses these three approximations: actions cannot mutate the application state, mutation is clearly defined, independent of assignments and action->model->state is "the" programming step.
So we can continue opposing shiny hammers, mixing up programming model, wiring, and architecture in the process, or we can discuss, as grown-ups, the underlying structure of our work. I'll choose the latter.
MVC is misunderstood
by
Andreas Söderlund
Re: MVC is misunderstood
by
Jean-Jacques Dubray
I appreciate when people are trying to perpetuate the legacy of Prof. Reenskaug, but it is now counter productive. MVC was designed in an other era (that I would qualify as "disconnected") and it no longer makes sense, either as a Design Pattern or, even worse, as a Software Engineering pattern. I agree that it has been used and generally misused in the last 40 years or so but it simply cannot account for an "activity-oriented" world where the a graphical user interface is just a node in a complex distributed system. There is no bridge that can connect a user to the underlying "model", even Facebook has lost control of the state-machine behind their client(s). At best a users can think in terms of events it is allowed to produce, they have no possible clue as to what will happen next. It's even hard for product managers and developers to keep enough control on "what happens next".
The idea that "views are created and coordinated by a Controller." is corny at best, mostly deadly. That, as a software engineering pattern, needs to go entirely.
Your idea about "reuse" is deeply flawed, if you have no clue as to factor your code for reuse, you obviously will not achieve reuse. SAM, for instance, breaks the mold of a "reusable" component into reusable building blocks. I have shown repeatedly that SAM's view components (organized as themes) are reusable across applications, so are actions, so are model acceptors. I can even easily wire 3rd party actions into my application. The non-reusable code is limited to state function that wires the application logic to the view components. It literally sickens me to read this kind of statement:
This means that we can couple MVC objects because they aren't on the actual level of being reusable.
You are sending generations of developers to jump of the MVC cliff for no other reason that you cannot think out of the (controller) box. It is actually this outrageous coupling that lead us to the concept of "templates" that is the worst drug our industry has ever invented. Scores of developers got hooked on it which lead to "runaway" code, where it was always easier to add another view than try to build reusable building blocks. In the last decade that poison spread to the back-end as APIs were designed to fit templates one-at-a-time. Before you knew it any medium size projects were tied to hundreds if not thousands of APIs. It was so bad that we had to invent a new pattern, the "vertical slice pattern", to at least make sure that we could keep some sanity in each of the hundreds of slices that were created.
And I could continue on and on, no the model should not know anything about the views, it is the state function who should managed the relationship between the model and the consumers of the model, which happen to be sometimes views (as view components in SAM). You may not have noticed that there is a static aspect to the model and a dynamic one and you get tremendous benefits when you keep both separate (decoupled as you might say).
No one "Can ask a Model for the current value of data it presents to the user", because as you might understand in a distributed system, the model is busy updating itself from another event. Thinking that there is no concurrency possible in a modern user interface is at best naive.
In SAM there is no "controller" (central coordinator) that for instance "Creates and manages Views", this is ludicrous. When an action is triggered, the action should only be responsible for converting the event into a proposal that the application logic can understand and process (another great decoupling between the view components which emit events and the model which processes proposals created from these events).
Re: MVC is misunderstood
by
Andreas Söderlund
Re: MVC is misunderstood
by
Jean-Jacques Dubray
Again apologies for repeating myself but "align[ing] the computer and the programmer (that sounds pretty nerdy to me?) with the mental model of the end user" no longer makes sense in modern application architectures.
MVC has shown repeatedly that it creates runaway systems where it's always cheaper to create yet-another-view (and now set of APIs to support that additional view) than creating application reusable building blocks. You even state clearly that any form of reuse is not only, a non goal, but it is impossible. Really?
In 2009 I joined a big bank that nearly failed because of a massive MVC-based CRM system they had built. That system required a team of 120 modelers (not even developers, modelers) just to keep track of the API interfaces that supported the views of the system.
Re: MVC is misunderstood
by
Andreas Söderlund
You, and of course many others as I state in my article, have clearly misunderstood MVC. There is no "true" MVC, that's another wishful engineering thinking. It's a pattern language. There is no "true" language either, see the difference?
A "set of APIs" for each view? What do you mean, a way of communicating between objects? Then every method is an API! That is surely taking that concept too far. (I notice you like to use the acronym though.) Also, you don't see a certain dichotomy here, there is a U-I and an AP-I?
MVC hasn't shown that it creates runaway systems. The massive "MVC-based" (sic) system you talked about was probably overengineered, overly abstracted and severely lacking in conceptual integrity. That's not MVC's fault. As usual, structure replaces architecture when the engineers gets to decide. Or, the project really needed 120 modelers. ;)
Re: MVC is misunderstood
by
Jean-Jacques Dubray
Re: MVC is misunderstood
by
Andreas Söderlund
The fundamental idea for the programmer's mental model was to separate the computer representation of the user's mental information model (the Model) from the parts of the program that facilitate the user observing and editing selected aspects of it, the Views.
Re: MVC is misunderstood
by
Jean-Jacques Dubray
Your attempt to perpetuate the legacy of Prof. Reenskaug is honorable, but these concepts are holding our entire industry back in a time where user/activity experience is key to building successful solutions and deliver experiences that anyone without a deep computer expertise can handle.
So again, today no one (users or developers) can think in terms of "views", or "model" (controller is an arbitrary concept without any tangible existence) but everyone can think in terms of "actions" and "state". State is the representation of the model that has direct physical connection.
The example I take to explain the difference between model and state is the one of an electric car. What does it mean for an electric car to be "started". Everyone would say, it just has to have enough battery, but not quite, it has to have enough battery to go where you need to go, otherwise there is no point in taking the action to "start" your journey. How could a user know all the rules that connect the model to a state? It's impossible even for software engineers.
That is the fundamental flaw of MVC, it's missing two key concepts: Actions and State which model precisely the interaction of a user or system with a information model. Trying to connect a user or even a system directly to an information model is pointless, actually that approach could not have been more flawed. It just took us 40 years and the incredible work of Dr. Lamport to figure it out.
Model as a class?
by
Dennis Davis
Re: Model as a class?
by
Jean-Jacques Dubray
apologies I just saw your comment. The SAM pattern makes a clear distinction between programming model, wiring, and architecture. There is, of course, no particular reason not to wire the pattern that way, but you would not change its semantics in doing so. The fact that the actions would be structured in a class is not implied, required or otherwise adding any value to the semantics of the pattern.
As a matter of fact I created a basic (but effective) component model where building blocks of the pattern are assembled in a static structure.
It's more important as an industry to agree on the semantics of the pattern:
- what is an action?
- are all assignments mutation?
- what is a programming step? (A-M-S? any line of code?)
FP, OOP, RP, FRP, ... are all missing a precise answer to these questions. TLA+ does, and hence SAM.
Redux + Thunks
by
Michael Ryan
Re: Redux + Thunks
by
Jean-Jacques Dubray









