Ask YC: is MVC the best solution?
Somehow my intuition is always a little bit at odds with MVC (as found in current web frameworks). It feels more natural that the view would request the data it needs, especially if it is putting together a mosaic of different sources.
For example, I guess most web applications have some sort of layout view and include the content into it. But what if there are different kinds of things to include? For example there could be a list of logged in users to be displayed in the sidebar, or any number of widgets. It seems unnatural to have to gather the data for those in every controller call.
My experience is with Java frameworks, where usually the flow is through one controller - how does for example Rails deal with that sort of thing? For Java I guess the proposed solution is Portlets, but I haven't seen their wide adaption yet, and they seem to be another headache (those Java specs should be made shorter and more concise).
What is the best solution?
19 comments
[ 4.3 ms ] story [ 49.4 ms ] threadThough I found myself, in many cases, writing more code than I would have without a framework, I found the maintenance benefit more than compensates.
Things have got more complex in recent years with more and more complex interaction logic embedded in webpages with Javascript and i'm not sure i've seen many frameworks address this.
Admittedly, there are now better frameworks out there than Struts (this was Struts 1) and I think i'll have to do a bit of exploring for my new project's website but we'll see.
Not trying to be a jerk, it's just a complicated question. I guess you mean greenfield web applications? Even then I'd have to ask things like how heavy you were client-side, what languages you knew -- most importantly, where's all the data? If you're delivering data basically from the server to the client and back, does most of the processing take place on the client or the server? Some MVC paradigms are crazy to push into Javascript. Some are crazy to use for simple projects.
Lately for Web 2.0 Applications, I'm using a framework that has a lightweight MVC (very lightweight!) in Javascript and pulls information using JSON from various sources. But I wrote it myself, so I'm biased.
MVC is a paradigm that can be applied a lot of ways, in a lot of situations. Most frameworks emphasize the controller, when the model is really what you're after. Your controller classes can "dumb down" in many scenarios to be so lightweight as to not require a separate class. Hard to do that with a pre-canned framework. I guess I would be extremely careful in confusing the framework with the architectural conceit it uses -- two different concepts.
In Rails, you don't necessarily have to have a monolithic view. On more complex sites, you use fragments, called partials. Sidebars can be easily created by having a "shared" view directory full of partials. Further, there is a content_for helper in Rails views. Views render late; you can set an instance variable in the subviews that will affect what gets rendered in the layout. Trying to keep track of that can get hairy, so content_for abstracts that for you. Combined with the partials and the before_filter in the controllers, you can get a view to produce a number of things without having to resort to pulling DB info inside the views -- that reminds me too much of the bad old days of PHP.
In the logged-in users example, in what is normally in the sidebar, you use a render :partial => 'shared/users' if @users; then add a before_filter in the site-wide application layout to pull in the data if someone is logged in. A more complicated example is to render a "sidebar" partial, which renders more partials depending on some array of sidebars you want to display ... then use a before_filter to figure out what you want to populate the sidebars with. Any controller or actions can override or add to that sidebar array.
The main thing that sucks about this kind of organization is having the code scattered in a number of different files. This is where using an editor that knows the relationship between the files is important -- you can hit some key combination and jump between the different fragments without having to hunt them down in the file browser.
I was helping out on this one site built in PHP a while back where the code wasn't organized this way. It took me about a week to figure out where things were, which was a huge productivity drag for the other guys.
A snippet from the README:
Unlike partials, embedded actions also let you define business logic to be performed before the partial is included. That logic is encapsulated in the already well understood metaphor of an action inside a controller.
So a simple call like
<%= embed_action :controller => "songs", :action => "top10" %>
lets you include an html fragment containing the top 10 songs into any of your pages, regardless of which controller, action or view wants to do the including.
----
In other words, you call "embed_action" from within a view which will call the controller-action and embed whatever result is there. You still get the organizational benefit of MVC without the hassle of rolling your own partials.
As an additional note to what I was saying about partials, Rails 2.0 also has a concept of "partial layouts", allowing you to switch out the surrounding content of a partial.
I would also say that this is one of the biggest drawbacks of current client side web frameworks. Reusing views is much more difficult than it should be, especially if you want to do anything remotely custom or complex, since subclassing is essentially not possible and delegates are very infrequently used.
Also, imagine an application with a Web view displaying a data set returned from a controller. Now the client/user wants an OS-native version of the app. That's simple, just build a native (OS-specific) window view and call the same controller for the data set (model). Or maybe an API is needed for external consumption. In that case a web service "view" can be built to return the same data set from the same controller. We're just swapping views here--it's plug-and-play.
It's a clear separation of responsibilities. I believe that used to be called "modular" programming. ;)
Caveat: My MVC experiences have been mostly with Java (Struts) and Python (Django) Then to get into your actual points:
1) The view CAN do the work of determining what will be shown. To quote the Django site: "In our interpretation of MVC, the "view" describes the data that gets presented to the user. It's not necessarily how the data looks, but which data is presented."
2) Anything that is a common widget should be abstracted and included on the page in some sort of "include". Either have some sort of base page that does the work, or on the individual pages do some method of "include". This really doesn't relate to MVC, other than your point about adding the data to your context/session, which should again be done generically and non per-page.
3) The general idea for any MVC system is to have the flow go through one controller. This controller may delegate to sub-controllers, but the idea is everything goes to one spot.
4) What is the best solution? There are many good solutions for writing a web app.
1) In Django the controller is called the view and the view is called the template, same principle but unless you want to get confused you should think of it as MTV == MVC (if you want to equate the two, Django seems to be perfectly happy making up its own interpretation of MVC for no apparent reason). Really the controller (in the MVC sense) is doing the work here.
The controller is doing the work to determine what will be shown, yes. I meant once the controller determines which view should be used, the view then can manage the specific data being shown.
Django does separate the view into a 'view' and a 'template'. One does your work, and the other does the displaying.
MVC is an elegant design pattern, but I think an MVC framework must provide a simple way for components to include other components. Otherwise, I can see why you would find it frustrating that your main controller has to do all the work.
Aren't these things conceptually separate views, each having its own controller?
However, mentioning MVC and web applications gives me an excuse to engage in nostalgia and once more mourn the passing[1] of WebObjects. It was simple in WebObjects to make any reusable part of a page into its own component. Also, MVC has a much bigger payoff when you have development tools designed to support it. WOBuilder allowed you to graphically build interface components, then just drag connections between properties in your controller object and the widget you wanted to display them in. And not just top level properties, but you could drill down through the relationships of any object (e.g. user.shoppingCart.numberOfItems, Google "key value coding" if interested). (And yes, this is just like Cocoa and Interface Builder, came out of the same technology base originally.)
I have yet to see any web development tools[2] that come anywhere close to the productivity enabled by WebObjects. And I didn't even get into the Enterprise Objects Framework...
[1] WebObjects is still very much alive inside Apple (iTunes store, Apple Store, pretty much everything Apple does on the web) but for outside developers it is quite dead. The only life support is ant + Eclipse plugins, but that defeats the whole purpose as the development tools were the whole point of WebObjects. [2] Tools as distinct from programming languages. WebObjects was Java, so nothing special there, but real old timers still miss the Objective C version.
If you, as you suggest, have the view (essentially a glorified HTML template) request the data it needs (e.g. from multiple sources), then your data-selection and visual-presentation become tightly coupled. (The point of a view is that you can have multiple views of the same data). If the original view is handling things like data-selection and complex control flow, then when you want to create an alternate presentation of the same data, you'll end up copy-and-pasting code (c.f. "Don't Repeat Yourself").
So the best solution is to get a really good feel for separation of concerns, code-non-duplication, etc., and then organize your code accordingly. When using MVC, use every bit of it to keep your code simple and decoupled; if you just slap code into units called "models", "views", and "controllers" wherever you like, then you will receive NO BENEFIT (or negative benefit!) from using MVC. But, used properly, it can be a powerful tool.