Hacker News new | past | comments | ask | show | jobs | submit login
Is Model-View-Controller dead on the front end? (freecodecamp.com)
238 points by lxm on Nov 11, 2016 | hide | past | favorite | 102 comments



MVC was originally designed as a pattern for desktop UIs. It has a single controller and a single model, not the MVC style that Rails popularized with one controller class and one model class for every kind of data. In classic MVC, Views query the Model for relevant data. The Controller handles user actions and uses that to update the Model, then asks the View to redraw (preferably in some smart efficient manner). This is unidirectional data flow pur sang and it comes from 1988. How is React+Redux any different from this?

I agree with the author that components are the true innovation of React, because it encourages reusable building blocks by default. Contrast with classic desktop and mobile UI toolkits which, while often also using or encouraging MVC, do not require the developer to not subdivide their own codebase into reusable widgets. Instead, they allow composing an entire screen (window, page, form, whatever) from the built-in widgets. Making a reusable widget is possible but extra work and therefore not done. In React, it's the only way to go.

This is awesome about React, but it has nothing to do with data flow architecture, which is what MVC is.

The mistake webdevelopers made for years was trying to shoehorn DHH's backend remix of MVC into the frontend, throwing away decades of UI building architecture knowledge. I'm happy the Facebook people rediscovered MVC and I'm even happy they gave it a new name (Flux) because MVC frankly has gotten way too many definitions.

But saying that Flux/Redux killed MVC is like saying Clojure killed Lisp.


If anyone cares, by the way, actually having a Controller has done wonders for our code at TalkJS. Our View is purely React components, all of which only deal with presentation logic and local interaction logic. The components query the store (Model) for data, like in any Flux/Redux setup and like MVC has encouraged for decades.

Then, user actions are handled in the Controller. In our case it's just a bag of functions. The Controller fetches and pushes data from/to the backend, and sends appropriate actions to the store. This allows us to keep all the backend data fetching/manipulation logic out of the View, which keeps the View clearly focused on the UI and the UX, and nothing else.

Our controller does not have read access to the store: any data the controller functions need to do their work is passed in from the view (which has the data anyway because it used it to query the store appropriately).

This works great, it's total unidirectional data flow, it's also pure classic MVC, and I haven't seen anyone describe it elsewhere. We came up with it 2 years ago when React was pretty new and I had little else than MVC to be inspired by.

If you have data molding code all over your views (and a little bit elsewhere too, for good measure), consider a controller.


Correct me if I'm wrong but I think what you have is described as an "action dispatcher" these days.

For what it's worth, I think, we can define the whole Flux architecture in somewhat-skewed MVC terms. Not trying to downplay the usefulness of Flux here but if I'm not all wrong, it would've helped many people if we kept at least some of the terms from MVC or MVVM.


Ah cool, thanks. Does the action dispatcher also interact with the backend? My understanding was that it just created little action objects and little more. Our controller is decidedly more heavy-weight. I'm not saying it's the best possible way to go but it's been working well for us so far :-)


In redux terms, your controller would be the bundle of "action creators". If you use vanilla redux, those would conduct all your "logic", including communicating with the backend. This has some pros and cons, so there are extensions("middlewares") to redux which iterate on the concept - redux-thunk, redux-saga, etc.

Since redux largely defines the design of the "Model" part and React largely defines the design of the "View" part, most of the variation when using React and redux is how to design your "Controller".


It is indeed very close to how you would model redux apps. Interesting that you mention that your controllers don't have read access to store(s). That is actually very common with redux-thunk or redux-saga.


AFAIK it doesn't, but I'm just learning. My understanding is the standard way of doing things work if you are creating the most boring CRUD apps but you need to "bend the rules" a bit to make it work for your use case very often - as long as you keep it newcomer-friendly.


> MVC was originally designed as a pattern for desktop UIs. It has a single controller and a single model

Not quite. Let me quote from "A cookbook for using the model-view controller user interface paradigm in Smalltalk-80" by Glenn E. Krasner and Stephen T. Pope, 1988, which according to Wikipedia defined the term MVC originally:

> In the scheme described above, views and controllers have exactly one model, but a model can have one or several views and controllers associated with it.


Good point!

All that said, they mean that you should use separate controller-view pairs for entirely different pieces of the application. A nice example would be MS Word's document editor (1 view with 1 controller) and MS Word's Print Preview view (same model, but a separate view and a separate controller).

What I was getting at is that in backend-MVC (and backbonejs-MVC), you usually build a view, a controller and a model for each domain entity (i.e. for each database table). This is fundamentally different from what Krasner and Pope describe, and it probably won't work well for the kinds of dynamism and interactivity most single-page apps are single-page apps for. I believe this is the flavor of MVC the author is talking about.

In our case at TalkJS, we don't have anything like a print preview - essentially our entire application is a pretty unified piece of UI (much like MS Word's document editor which, while complex, is pretty much inseparable), so we have only one controller and one root view. I made the thinking mistake that most UIs only have one root view, and of course that's not true. So thanks for that.


The Model, View, Controller terms were originally defined by Trygve Reenskaug in 1978, based on his Smalltalk involvement, and formalised as Models-Views-Controllers in a 1979 paper.

He tells the story on his homepage: https://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html


> I'm even happy they gave it a new name (Flux) because MVC frankly has gotten way too many definitions.

Sad because there are too many definitions? Nothing a new name can't fix!



>Nothing a new name can't fix!

If a new name catches on and puts the plethora of older names in the dust, then it CAN fix the "too many names" problem.

And Flux seems to have latched on well.


% MVC was originally designed as a pattern for desktop UIs.

i still remember the MFC class library for Visual C++. it needed MVC for MDI applications where you have multiple document windows within one application window. Later MDI (and MFC) went out of fashion.

Later MS had ATL and WTL and here they had no MVC. i think not all C++ GUI class libraries were model/view/container, borland's wasn't

Also java class libraries for GUI did not force MVC. Awt and Swing don't do that.

Therefore MVC is not the only paradigm used in GUI frameworks.


Last I checked, Borland's widget library (their "Visual Component Library", or VCL) was, like React, View-only. The idea was that the view is the hard part and you, the coder, can choose how to structure the rest of your application yourself.

So sure you can put all data management right inside your Delphi form, and plenty of coders did this. You can do that with React too. But larger applications often chose to go with MVC, where the appropriate fields inside the VCL components were updated triggered by changes in the model.

It's nearly entirely the same model. The view classes (Delphi components, forms, etc) can render (by setting attributes on widgets) and have event handlers (eg onButtonClick) which in turn invoke the Controller, which makes appropriate data changes in the model.

Nothing in Delphi enforces this, but it matches really well. Thne only big thing they missed was something akin to a Virtual DOM and shouldComponentUpdate, making figuring out which fields to update when cumbersome. But there's been plenty older solutions to this problem (such as damage/repair).


It's probably evolved a bit, but when Delphi had big momentum most developers used data-bound components that updated directly from DB view queries and whatnot.

There were complex components that did transformations on the data for reporting or complex grid displays, etc, but generally you didn't see an abstract formal model behind forms/views. If you did model outside the DB, you did it in such a way that the model looked like a database table or query (subclassing abstract DB proxy components the VCL gave you) and used components directly bound to that.

So, I guess in MVC terms, what you had was a form implementing View logic with components directly working from DB or DB-like data, and controller code behind the form doing event-driven manipulation. The controller code could hook data events too, and in that way reacted to "model" changes as well, but the "model" was actually hidden in DB bindings and components. For any model business logic more complex than you could handle this way, middleware was usually pushed.

This may have progressed since the early 2000s when I lost track of Delphi, but the idea of directly-bound display components was typical of the dominant DB-driven 4GLs of the time, including Powerbuilder and VB.


The absence of standard widgets makes React awesome?

People compose an entire screen from built-in widgets because usable widgets and layout algorithms make this possible. If you are trying to build more complex screens, people in "classic desktop and mobile UI toolkits" also build own widgets.

Projects like Material-UI are finally dragging frontend development into the 1990s of "classic desktop UI toolkits", only the layout functionality is still sorely missing.


I agree to almost every point, but note that in the MVC definition, each of the M, V and C are components, not classes. A component may be composed of several classes. So there's nothing inherently wrong with Rails' approach.

I just think that as opposed to the original idea, people started to stuff way too much into their controllers, which is what makes things messy. I agree that Flux helps enforce the way it was supposed to be.


On the contrary, I find that people stuff too much on the model because of rails. I've found that I much prefer very simple models to describe very fine grained parts of the data and use the controller for much of the tying of things together. You kinda of treat models as 'data components' if you will, mixing and matching them where needed in the view


That's the "Massive ViewController" anti-pattern (or just massive controller, if you're not in Apple land).

Classic MVC is really MVc, with controllers only handling a small set of interactions that are not directly between the Model and View, for example dialog boxes and such.

One problem with a "Big-C" approach to MVC is that whereas models and views are at least potentially reusable, the controllers are dependent on both M and V, and thus both proliferate and are not reusable.

Glue code. The dark matter of programming.


Hmm, often times the models are not reusable because they end up doing too much. Tryg actually started to create something called ACI because of this.


+1

Everything right now is just MVC-like. Yes you have some unidirectional PUB/SUB here or some immutable data structure there.

So what ? In the end, you still have the separation between the data, the way you manipulate the data, the way you display the data and a canal of communication for those.

This is the essence of MVC, and what everybody is doing right now is just a variation of it.


> How is React+Redux any different from this?

You could say Redux is a more constrained subtype of the 'single data flow MVC' you describe, which in turn is a subtype of 'all definitions of MVC which have existed'. In Redux actions are serializable, which opens up a bunch of other possibilities. Not to say Redux invented that idea by any means (it's the FP principle of separating data and behavior, also the OO command pattern), but it's useful to have a name specific name when talking about a more specific combination of ideas/constraints, especially if those constraints make different things possible (undo/redo, replay, logging/analytics for free).


Very well said, but MVC is from 1978, not 1988.


Firstly, I'm not sure it's an entirely accurate description to call Smalltalk-80 (where MVC was invented) a desktop UI given how unfamiliar it would be to users of MacOS or Windows.

Secondly, MVC was certainly not invented in 1988. It was a product of the work at Xerox PARC in the late 70s.

It's worth pointing out that Dan Ingalls and Alan Kay and other pioneering people involved in Smalltalk ended up 'repudiating' (to use a strong phrase maybe) MVC in later versions of Squeak (which is a direct descendant of the original Smalltalk-80 implementation) uses the "Morphic" GUI system which was built for Self at Sun in the 80s.

Morphic is a prototype oriented, direct manipulation system.

None of this has historically translated well to the web, where the HTTP request cycle and the nature of the DOM and JS execution model changes things significantly. MVC was never a good model for the web.


Note that React is enforcing functional programming principples. Stateles and immutable objects by default. Thats was not how it was done in 1988.. In react the views doest fetch new data... The whole view is regenerated when there is new data. In a functional style.

But i agree you could fit React in the MVC pattern. Only the view is purely functional.


FYI: I've decided to further elaborate on this argument a bit in a blog post: https://blog.talkjs.com/how-react-brought-model-view-control...


> trying to shoehorn DHH's backend remix of MVC into the frontend,

That's basically what Backbone was and yes it led to a fn disaster.


Same for REST. Rails is one main reason why people think they use it, when they are actually not.


Its the same pattern. The whole point of MVC isn't the damn precise implementation its about separating out the concerns of the view, the services/data and a thing or some things that control and/or glue it all together.

The point is to not munge all these things into one monolithic horrible grim mess. As long as you are separating the concerns of showing something to a user, allowing them to control it and backing it all with potentially remote service who cares what the pattern is precisely called? Its still flavours of this original desire that we named MVC.

All these presenter/unidirectional patterns are _just_ the underlying desire of MVC and the only reason that people seem to talk about how "MVC isn't right" or "is dead" is because they've followed MVC like dogma instead of just a guideline of separating your presentation, control and service logic. I had exactly this debate back when everyone was talking about MVP as if it was some revolutionary new thing. Its not, its all the same thing and GOF was never supposed to be a template for software but a way of talking about specific ideas that architects could then riff on. They're chords, not one specific tune that you _must_ play in a very specific way.


I agree completely. If you model is echoing long bits of HTML, or your views contain lots of SQL, that's not really MVC. Almost everything is just details. We get excited about labelling them as 'ADR' or 'MVVM' but they are all just variations on a theme.

Perhaps the problem is that rules like 'no SQL in your views' is now so ingrained, a lot of juniors have never seen a monolothic mess of SQL mixed with HTML. So MVC is almost ubiquitous, and we then try breaking it down into different sub-categories.


>> SQL mixed with HTML

And now we have Javascript being mixed with HTML; which I never thought would happen.


JavaScript isn't a type of logic, it's a language. You wouldn't say JavaScript is the M in MVC, for example. If you have JS in HTML, and that JS code is strictly view logic, then your code still has a clear and useful separation of responsibilities.


> now we have Javascript being mixed with HTML

Now we have JavaScript mixed with an HTML-like syntax.


It's funny how this anti-pattern like has become so widely accepted.


So...according to your definition MVC == encapsulation ?


> As more and more developers start to see the advantages of components and unidirectional architectures, the focus will be on building better tools and libraries that go down that path.

"Unidirectional architecture" is a weird name for what is a fairly standard abstraction. Every front-end at the top level is:

    f(my_entire_state, some_event) -> my_entire_state'
In the end all you need are well defined state transitions, an event bus and a main loop to connect the two. Persist the sequence of events for undo/redo, audit, debugging ... and the current state for caching or having durability between sessions. Push side-effects to the boundaries. You may find this is good enough.

Front-end development has been plagued by unclear patterns w/ weird names (MVC, MVVM, MXYZ...) since forever; everytime the patterns are criticized you hear "you did not understand it"; and new names keep popping up. It seems the industry is stuck remixing reasoning around nouns, and is unable to step back and reason around data.

BONUS: Sprinkle some CSP to get elegant concurrency, throw away callback-hell. Sprinkle some React to get fast DOM manipulation, throw away Flux (heresy!) - it has way too many names to worry about (action creator, action, dispatcher, callbacks, stores, store events, views) and encourages some bad practices around use of stores.

My $ 0.02


The CSP thing is something I've been looking at recently, and while it seems like it's a little bit lower-level than things like Rx, it seems like channels are more flexible streams (i.e. channels are two-way so you can do back-pressure etc.). I've been playing with https://github.com/ubolonton/js-csp and it's pretty nice; the "yield" statements everywhere are a little wonky, but otherwise it seems like you can implement some pretty sophisticated concurrency between processes with pretty straight-forward code.

For examples of that sort of thing, David Nolen and James Long have written some really great articles on the subject:

http://swannodette.github.io/2013/07/12/communicating-sequen...

http://swannodette.github.io/2013/07/31/extracting-processes

http://jlongster.com/Taming-the-Asynchronous-Beast-with-CSP-...

There was also an article recently that described a flux-like architecture using channels that I found pretty interesting, but I can't track it down right now.


Those articles are excellent and held my interest since they were published, but at the same time React and Flux were exploding and I never saw any further talk of modeling UI logic with processes and channels. It is still in my notes: Take another look at Hoare CSP for UI programming perspective. I once asked David Nolen on twitter if he thought the CSP approach is still useful given the perspective of React/Om. He said yes but that was the extent of the conversation.

In particular, I have yet to see any examples of integrating the CSP approach with React or similar architectures. For example, can you hook a process-based autocomplete widget into a React view? Is anyone doing this or have we rejected CSP for UI logic? I am interested if you can find article you mentioned.


David has moved away from it, in OM.next you do not use CPS. You can of course, but it would only be a implementation detail and not fundamental to the structure of Om.next.


I think that's what I'm driving at: apart of the Om architecture itself, does it make sense to drop something like a CSP autocompleter into an Om app, or are those things incompatible?


Well said! I find that https://github.com/Day8/re-frame combined with statecharts fits the bill and makes for some incredibly clean and enjoyable UI development.


How do you architect your re-frame apps? How do you decide where dispatch/subscribe gets called? I ask, because having worked on a couple of re-frame (and indeed raw reagent) projects, I often see issues of layering and responsibility that MVC traditionally solved.

For example, I regularly see subscriptions deeply nested in the component hierarchy, instead of more 'pure' components that just accept data at the top level. This leads to controller-style logic spread all over the app. I see the same issue with events - dispatch being called from inside view components, and despite the event abstraction, what you basically end up with is mutable state spread all over the app.

Happy to admit these apps probably aren't shining examples of react/reagent/re-frame architecture, but I'd be interested to see some canonical architecture guidance.


If the only tool you have…


It's in times like this that I'm glad I don't blindly follow the hype. According to the consensus, I should have gone with Backbone.js in 2011 (then Knockout, Ember, Meteor, Angular…)

I'm still not completely convinced by React, and I may very well be wrong, but the same skepticism that sometimes makes me feel out of touch, also provides some sanity in this madness.

For some reason that I can't quite point out yet, Vue.js feels like the nicest one yet, though I've only played with it briefly.


If you went with Backbone.js (or similar) you would have been better off than the standard bag of jQuery methods. Curious what you ended up going with back then?

Most projects I start these days tend to use React. I've looked into Vue, and liked what I saw. I also maintain a 5 year old project built with Backbone.js (by someone else) and I'd say it checks all the boxes for maintainability, stability, and testability. It has its flaws -- as any old codebase will -- but I'm happy they went with Backbone. I'd probably be saying the same thing for the other frameworks mentioned.

Its easy to point out all the flaws from our past. Much more difficult to predict how thing will be in the future. Making a choice now, even the wrong one, is almost always better than clinging to things that are known to not work.


Still rocking jQuery whenever I can. It can grow into an unmaintainable mess, sure, but it doesn't have to.

First time I saw jQuery: Crazy easy and widely compatible, Ajax, selectors and animation - sold!

First time I saw React: Split your UI into components, write them in JavaScript (with optionally mixed in markup to make it more tolerable) - Hmm O…K….

Managing UI state can be complicated, but to me, not enough to justify the amount of complexity and abstraction added by React. If you organize your code so that only a single function can act on a specific block and emulate OO/namespaces in CSS, instead of attaching functionality to every click and overwriting stuff with !important, you'll be fine. It's not that hard, but maybe that's just me.

It's nice that the Virtual DOM is really fast (even thought I don't usually need that much speed) and that I can render it on the server (even though you can probably kiss your semantic markup good bye) and one way data binding seems a good idea, but again, I don't think it's a problem I have.


The "jQuery === bad code structure" association is strong, even today. But the fact is you can write good code with jQuery – without Backbone – just fine.

Most all web developers of that day were new to programming (experienced folk didn't take JS seriously), so naturally they did not know how to write well-designed software. The benefit of Backbone was not Backbone itself – it was the community push for thinking about code structure in general.


Exactly! So many people assume that the emerging of a new "best" way of writing front-end software renders all previous architectural decisions wrong.

It even came to the point that some people reject using any frameworks or even a helper like jQuery and "take everything under their control" because they don't want to deal with "deprecated" libraries.

Meanwhile, a small development team I know keeps using Knockout.js successfully in huge projects.


I'm a web dev since the beginning. Of all the frameworks I've worked with, Knockout has the most utility for the least obtrusiveness.


Yeah, anyone who rejects jQuery in ie8 legacy rejects has screws loose, or a massive ego problem.


I recently started diving into Vue.js (2.x) It's fantastic. It's a utopian Angular1. The html syntax is fairly similar, but cleaner and less verbose.

Vue-router is what really got me into it. Again, it's similar to UI-router for ng1, but destroys it in simplicity and readability. I'm using their vue-webpack template to rebuild my site and it's going great.

Personally, the best thing for me is that a component gets nearly everything it needs in one file. Template, script, and scoped styling? Exactly what I've always wanted. Forgive the gushing review, but honestly, I haven't ever been this excited about a technology. Not ng1, not webpack or es2015, or [fancy new tech]. This shit just works.


"According to the consensus, I should have gone with Backbone.js in 2011 (then Knockout, Ember, Meteor, Angular…)"

The best investment that I ever did was really learning JavaScript and all it shortcomings. The problem with a longer younger colleague's at work is that they seem to learn frameworks instead. They can make cool stuff but from the moment they are in situations where for example "this" does weird stuff, they don't know why or how.

There is nothing wrong with using frameworks - I use a lot of React these days, before a lot of Backbone - but if you know enough JavaScript changing between them should not be a big deal.


That's the problem with all abstractions.

The abstraction gives you hope that you won't have to worry about the low level details, it will be so easy.

But almost invariably, the abstraction breaks down or acts weird, or some low level error or limitation bubbles up, or the abstraction has horrible performance for some edge cases.

So now, where you had 1 problem - the low level thing - you have 2 problems - the low level thing, and the abstraction.

You don't have to be a uber-expert in the low level thing but it's really helpful to be comfortable with it.

I see it with ORMs - 'wow this is magic, I never have to do SQL again' - 'oh crap, a weird edge case, I have to do SQL' - 'oh crap, why is this so slow, guess I have to look at the generated SQL, and maybe hand-roll my own'.

(Not saying you shouldn't use abstractions, they can save a lot of work for the central cases where they work right.)


My take is you should be skeptical but don't let that skepticism stop you from learning something new.

I remember the complex UIs I and others wrote a decade ago with jQuery, now those aren't complex at all compared to what is common now. I feel that it isn't quite fair to say that back in the day we got along fine with just jQuery.

Speaking of Backbone, I was already more or less organize my code like Backbone for a year when it came on the scene. Then there is the question, can I really program a custom framework better than an established framework?



The whole "x is dead" is pretty common headline pattern. It's dramatic, extreme and often just an exaggeration.

I can guarantee that MVC is still used on the fronted as on the backend. People are still generating value from MVC apps.

Perhaps it's not held up as the holy grail, since the new holy grail is pronouncing it dead. Perhaps it is dying. Dead it is often not.

After building out some front-end MVC work, I can see the value in Flux architecture and React components. I'd have a hard time justifying a rewrite though. It's still very much alive there for me. That's also the case for many others.


At the moment I'm sold on Mode-View-Intent, which is more delarative and non-OOP. I also have the feeling it lets me compose a bit more easy.

    DOMStream = view(model(intent(DOM)))
    DOMStream.subscribe(render)
intent() takes the DOM, wires up some interactions and returns streams "of" these interactions

model() takes streams of interactions, wires them up with data retrieval and mutation streams and returns these data-streams

view() takes the data-streams and uses them to create DOM mutations-stream, which it returns.

The nice thing is that these observable streams are really nice to filter, map, debounce etc. Also, it helps with fast realtime data stuff, because you can easily wire up these fast streams with a tiny part of your app and the rest of it won't even notice (which is a bit ugly if you got a big state-tree that represents your whole app state).

The not so nice thing is, that controlling them completely declaratively has a steep learning curve.


> model() takes streams of interactions, wires them up with data retrieval and mutation streams and returns these data-streams

I think that's called a controller or presenter in other patterns.

Actually your view and intent also do what a controller would do. The DOM is your actual view, and your data your actual model.


You're right, the names are badly choosen.

In every function the same is happening, streams are created/wired up with other streams.

The differentiation here seems to be, that the Model function just wires up streams for the data, the View function just wires up streams for the display and the Intent function just wires up streams for the interactions.


I closely follow the Elm way (but in javascript with React), and it's still pretty much MVC.

  Model = the state,
  Controller = the update function changing the state based on action.    
  View = declarative, need to send actions to change the state. Gets redraw on state change.
Redux/flux are also similar.

The idea of MVC, as far as I'm concerned, is to separate the View (Declarative as much as possible), the State (Just data, no logic) and the Controller (Business logic receiving commands/actions/called/whatever which changes the states and let the view knows that it needs to update).

Is that pattern dead? Far from it.


But how do you update the view efficiently, and robustly (without introducing bugs or becoming less efficient as your view becomes more complicated)?


Well, this is exactly the goal of this pattern.

One thing I didn't mention is that I use MVC per component, not for the full application. (I use something else for the global Application level).

So, every major component has its own MVC. I.e. One page on mobile listing a items with a bunch of interaction would have its own MVC.

And why it's robust and efficient:

Very easy to reason about the data and write unit tests. The whole data is in the State, and only the controller can alter that state.

The view is completely decoupled because it can't change the state, it can only declaratively render something (we use React with immutable). And this is also very easy to test and mock with fake data.

As for performance, I've tried various strategies over the past few years, and I find Immutable data structure + virtual Dom pretty damn amazing. I personally use React.js + Immutable.js, mostly for the great documentation but this is definitely not the only libraries.

And if the view becomes that much more complex, then it's time to spawn a new component with its own MVC.


I don't think that works well if the view is a complex function of the state. You can break the MVC into smaller components with an inner state, but how do you know which components to update when the outer state is updated? I believe you can't know, unless you duplicate the complexity of the smaller components into your larger component.


From what I understand, react + redux has a couple of tricks up it's sleeve.

As the components don't hold state, only display the state of the model (part of the redux store state), components only need to be re-rendered if the state has changed.

If you combine this with reselect (https://github.com/reactjs/reselect), then this allows you to only re-render components when the sub-set of the state tree is changed that can affect your component.

So to a certain extent you're registering your component's interest in a sub-set of the state, and then only re-rendering when that sub-section changes. The trick is then to ensure that as you build your app you don't build a single component that depends on everything and pass state down as props, but lots of smaller components that depend on a small sub-set of the tree.


Does that also work if the dependence on the state tree is not hierarchical? I.e., subcomponents referencing the state in a random-access way?


It would be much easier if you provided an example of what you have in mind. The approach I mentioned work perfectly for us, but it doesn't mean it'd work for you.

But to answer your question, it shouldn't matter if subcomponents reference the state in a random-access way. Our workflow is like this:

a) Main components fetch data from an external module. (That module either queries the server, gets the data from the client database or uses something already in the memory cache).

b) That main component generates a ModelView state. Basically, it transforms the fetched data into something it can use. It could mean joining models together, etc.

c) The view uses the ModelView state to render itself. Each component generates a virtual dom representation and then renders themselves in the DOM.

d) Now, there are two different ways this ModelView state can be altered:

  1) From a global event (eg. New changes came from the server. Or a component elsewhere in the app sent a global event.)

  2) From the component itself (eg. An event/action is sent from the view)
e) Either way, once that ModelView state has changed because of that event, the view gets re-generated very efficiently. I.e. Only the small part that visually change gets rendered.


I have the feeling I am reading Vogue describing what should be the new trend this winter.


I have the feeling fashion entered the IT world in the era of the first tech bubble when being a geek suddendly became synonym for being rich, and open source technologies started to do marketing instead of white papers and specs. Not sure it's the best thing that happened to our field.


Note that FreeCodeCamp'a entire existence model is teaching people the trendiest thing so they can get jobs.


Agree.


A component, a la React, is merely an opinion on MVC. M are props, and V is a pure function of these props. React encourages both M and V to live in the same file, which is a deviation from best practices in MVC land. But there is still an M and a V.

C, in the front-end world, has less of a direct equivalent, but can be thought of as your router, which React also has as a separate entity.

What MVC does not have an opinion on, is that the M is really one giant object, where each component receives a sub object of it. Where MVC can go wrong is when many objects have dependencies between their state. React comes along and says that two objects with a dependency should derive this shared state from something above them, not inside them. This is a useful pattern. It is still merely an opinion on how to organize Ms in an application. It is not something "different".

In functional programming, in its purest sense, there is no M. That's different.


I'm a bit confused by the way the article describes MVC as going from "server-side" to "front-end" :)

When I was growing up coding native UI apps, MVC was all about front-end. UI toolkits were traditionally MVC or M(V+C) going all the way back to SmallTalk, and "server-side" typically meant apps without "V" or a "V" that was so small and hardcoded in without separation...


Am I the only one thinking this kind of discussion is not hitting the nail on the head? I think the main issue with web UIs is the lack of good UI design tools, and nice and robust components. When I am developing a UI I am spending a lot of time writing code code while I just want to drag and drop components.


The problem with that is always what the frontend kids call "responsive" these days. The D&D editor doesn't infer a layout, so when you resize stuff stays the same or everything resizes equally, which is terrible.

I think the XAML approach was ideal, where you had a design view that showed a rendering of your view and allowed to make property changes and D&D controls, but also had the source to properly use grids and other layout managers to align and resize components.


There are products out there that work like this. Our product, Elevate Web Builder, is one of them:

http://www.elevatesoft.com/products?category=ewb&type=web

although I'm not sure how many more there are that aren't hosted directly in the browser, as opposed to a standalone IDE that runs on a desktop OS.


When has drag and drop ever worked for any programing environment?


VB6? Delphi? Windows Forms? WPF? Flash? QT? Xcode?

I am not saying I don't want to write a single line of code, just saying that the UI components can be assembled and "configured" with a design tool.


Having started on Android and then gotten into a Delphi environment, Android development tools seem like they're directly evolved from Delphi.


We've sort of evolved in our stack, which leans heavily on two less-popular options (MobX + Horizon), towards a pattern that I now think of as invaluable.

I started calling it Model-View-Store recently as I think that best describes it. There are a few unique things here that I think are valuable.

Starting with Models: Models all return observable values. So if I query for a single record I get back an observable object, or a list, observable array. I define `@query` decorators on the models to set up these queries. Model's include prop validation, normalization, consistent operation names, and more.

Views come in two types: application and presentational. App views are all decorated to automatically react to mobx observables, so you can literally have a Model `Car` and in a view call your query `Car.latest()`, and your view will trigger the query and react to it accordingly. One line model <-> view connections!

Then you have Stores: they are just logical containers for views. Any time a view needs to do more than some very simple logic for a view, you can attach a mobx store to it with very little code. Stores also can manage the data from the Model (and because the Model returns observables, this is usually a one-liner). But they don't have to. Stores are located side-by-side with the views they control (and are be passed down to sub views when needed).

I've been working on this system for a bit now along with our startup and we've been able to deliver some pretty incredible stuff very quickly. Having a consistent model system is crucial, I can't imagine programming without having prop validation and a single place to look for my model queries.

Going to be releasing pieces of it over coming weeks and hopefully a full stack example thats really legit soon.


I worked with MVC before, but eventually I found that DDD (Domain Driven Design) is what I'm looking for. Domain Driven Design is more like a set of rules of how to apply the existing design partners (eg: repository, factory and aggregation) and building blocks (eg: layering architecture) to design your business models and keep the integrity, invariance between data. Moreover, it lets you easily define the boundary between your services for Microservice architecture.

MartinFowler DDD blogs: http://martinfowler.com/tags/domain%20driven%20design.html Book: https://www.amazon.com/Domain-Driven-Design-Tackling-Complex...


Isn't this akin to what has been called MVVM in WPF land, or Presentation Model pattern by Martin Fowler, both more than a decade ago?

You have Model, View, ViewModel, and whatever auxiliary libs those need.


From a comment to the article:

"The unidirectional data flow approach that’s in the spotlight right now thanks to Facebook is actually pretty darn close to what “real” MVC (as in the design pattern introduced first in Smalltalk decades ago and not the “server-side” appropriation that frameworks like Ruby on Rails popularized) is."


Exactly. If you ignore misappropriation of terminology like the server-side "MVC" frameworks that had very little to do with MVC, and you ignore modern buzzwords like "unidirectional data flow" for the old idea that interactions update the model and that leads to updated rendering, then front-end web development today is following a broadly similar path to what general GUI architectures and visualisation tools did about 10-20 years ago.

People have noticed that views and controllers tend to come in pairs, and experimented with how to set up the controllers to receive events without creating excessive coupling.

People have noticed that you often want some sort of intermediate state derived from your model to support your view rendering, instead of regenerating expensive data from the model itself each time you render.

People have noticed that rerendering everything can be a bottleneck and developed tools for identifying only the changed areas to render selectively.

Tune in next week for: Immutable data structures are relatively slow. Large-scale declarative rendering is relatively slow, even if you use diffs. Fine-grained publish/subscribe models are relatively fast, and flexible enough to cope with both computing derived state and triggering UI updates, but you need good tools and a clean design or the edge cases will overwhelm you. Small-scale declarative UI updates triggered by a fine-grained publish/subscribe model is a useful approach in a lot of cases. And everyone hates temporary/transient state in forms.


We went the reverse: fine-grained to coarse-grained. The "aha" is that the speed is just not a big enough deal for most cases. Consequently, go full declarative for the 95%, and only go fine-grained for the 5%. More concretely: we went from mostly Rx to mostly React. Both have their strengths, but it's not a 50/50 thing in terms of lines of code.


In my experience, it depends very much on what you're doing.

If a UI has light to moderate rendering requirements, React's approach might be fast enough on its own. In that case, a lot of the other ideas are just extra complexity for no real benefit. I'm speculating here, but I'd guess this actually accounts for a large majority of the web front-end work that is being done today.

I haven't found that React alone scales very well to more demanding environments, though. If your model has significant constraints between the data points that need to be enforced or you need non-trivial view-state between your model and your rendering code, you're back to having dependencies in the data that need to be implemented somehow. That is outside React's scope, so something else needs to bridge the gap.

I find React's design itself also struggles with scaling up beyond a certain point, though it's a high bar that I expect most UIs running in browsers wouldn't reach. However, if you're implementing something like a complicated dashboard with many data dependencies and interactions, you start needing shouldComponentUpdate almost everywhere to achieve acceptable speed. That has profound implications for how other parts of your app are structured because you need some way to make shouldComponentUpdate fast, and it can also lead to more and sometimes artificial subdivisions of your rendering components so you can use shouldComponentUpdate at the necessary level of granularity.

Overcoming those scalability issues usually seems to bring me back to the approach I mentioned before for larger, more complicated UIs: data dependencies are handled through some sort of observer model and/or lazy queries, but a library like React is still useful for declarative rendering of each smaller part of the UI so you don't have to worry about transitions most of the time.


FWIW, it's worth considering we (graphistry) work at the edge of what is possible in browsers. We hook up GPUs in the client to GPUs in the cloud for an unprecedently rich visual analytics experience. Think building Netflix, Photoshop, or Google maps for data. If mostly react and falcor, with only sprinkling finegrained rx, is how we handled the perf and composition mess, I'm pretty sure simpler apps can do even less than us.


Looks interesting... You're doing statistical visualisations using WebGL and GPU acceleration? If that's right, would you mind sharing a little of how you're setting up your overall architecture?

The web projects I'm working on are in a slightly different field. We also seem to be pushing the practical limits of browser-hosted GUIs with some of our interactive visualisations, but they tend to use SVG. WebGL is one of the technologies that is definitely on my "could be interesting/useful" radar, but I haven't tried to do anything serious with it yet, so I'm wondering how different a real-world-scale project would be.


IMHO it's somewhat orthogonal. You can can use the MVVM pattern with unidirectional data flow, where it's always obvious how data flows from a model/service to a viewmodel to a view. And were views only trigger model/service updates and never directly manipulate the shown data.

You can also however use MVVM with kind of a spaghetti data flow or apply unidirectional data view without MVVM.

I personally like MVVM a lot, and it also fits very good to the latest UI frameworks (Angular2, Aurelia, etc.). I would also always try hard to achieve a purely unidirectional data flow. I however don't care about whether to use Flux, Redux or anything else for that. In fact traditional services (aka implementations of some interfaces) that encapsulate a specific set of state work very well for me.


For anyone interested in a surprisingly pleasant to use front-end MVC framework I am a huge fan of http://mithril.js.org/.

It espouses a (I believe?) slightly more traditional MVC interpretation where your Controllers are usually extremely light and in most cases completely optional. It encourages a MVVMC (Model View View-Model Controller) approach to encapsulate view-state.


I think there is a problem defining MVC. If you argue that current innovations in the frontend do not violate MVC, then MVC is a very useless term. If you think of an very conservative, OOP definition of MVC i don't think React fits the model. Of course that means that many other frameworks are not truly MVC, but MVC-inspired, but i don't have a problem with that.


Great article, couldn't explain the pain better. I worked a lot with Angular1 in the past couple years, and the controllers tend to get very messy because a lot of ui state and app data mixed together in the controllers. I am using React for most of my apps now, but I look forward to see what frontend architecture will come out in the next few years. I feel as ES6/7 is getting more and more common for js development, probably some OOP patterns that are used in Java/C# will be developed for frontend, but of course, front end apps is still different from Java server apps because of the nature of the language and the purpose of the app (frontend is more view and user interaction oriented)


Agreed. MVC has always been sort of an awkward pattern for frontend web development. The fact that the DOM is extrinsic to the JS runtime can lead to a messy collaboration of MVC components. An input that makes an AJAX request on each keystroke and renders the results to a list (typeahead.js for example) is easy to implement but involves quite a bit of indirection with this paradigm.

That being said, I don't know how to feel about Angular 2's approach to components. Decorators are useful but can diminish the benefits of component based architecture when misused.


> The Controller is highly dependent on the View.

OP is painting with an overly broad brush: Angular is not representative of all client-side MVC. I maintain an app where the view handles the browser events - as it should, and the only data that gets passed between the view and the controllers are the (business) models.


On android, MVC is dead. Talk about overly-circuitous code that is not straight forward to step through. MVP is great, when not over-done by folks as well (eg making a model-view-presenter unit recursively for every element on screen rather than having one unit associated with the a given screen).


So what if anything COULD replace components and unidirectional architectures in five/ten years?


I wouldn't say MVC is dead in the front-end, rather I would say MVC is a necessary stepping stone towards modern front-end architecture. It still has some kind of model, view and whatever the controller is called.

Before the time of Single page applications, MVC was not practical as the state of the page would be destroyed as soon as you click on a link. With the whole "single" page approach your page lives on and your applications remains. This was the considered the "holy grail". We are thought all the problems are solved, but then came the performance and memory leak issues. Because the page lives on throughout the user journey, memory management became a problem.. and so was SEO. As always front-end will continue to change rapidly year after year and it's now all about Flux/Redux and Universal javascript?

Saying MVC is dead is like saying "CPU" is dead, no it's not, but it will always keep on improving.


Well, we still use Models and Views, but not with React or Rails, no no no. With classic ASP. Also I'm not sure as to where the line is being drawn between frontend and backend...


MVC never made sense on the frontend, unless it was a completely silo'ed frontend app with no backend.


i write ember code and for me it still lives a lot, though MVVM


MV arises naturally. You can run the entire application logic without UI components, and you can test it that way also.

Other abstractions are designed similarly to allow tests against pieces of the internal API in total isolation, though separated on different lines. Maybe you have transient state stored in view models while persisted state is stored in models. The isolation only helps as size grows, and it can keep size under control mostly by having a good data model for what each component / layer / aspect actually does.

It makes it easier to rewire everything when you start with a switchboard. UI changes are either "Oh my god we're going to have to re-write so much stuff if we do it that way!" and you wind up not making drastic UI changes or "Sure, we can make that thing tickle the controller instead of that other thing."


Yes, and good riddance.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: