Archive for November, 2014
Note: I wrote this March 15, 2009 but never bothered posting it until now. -Sean
The model is the data storage and the logic for handling it. It is not dependent on the view or the controller, but is accessed by both. It includes the database, whatever it is, and the data access layer. Data objects should know how to get themselves, update/save themselves and present their data to the application. There are several ways to model the data access layer, one of the most popular being the Active Record pattern (http://en.wikipedia.org/wiki/Active_record_pattern). Because most applications are essentially about finding, displaying, and changing data, the model has been called the “functional core of an application” (http://www.phpwact.org/pattern/model_view_controller).
The job of the view is, when the controller passes it a user’s interaction (request in web terms), to get data from the model and display it for the user.
It follows that, in web programming, views should only be handling GET requests directly.
When people submit data to a form, we often need to give the user feedback on what they have submitted. This suggests either a tighter coupling between “controller” and view, or a way of representing in the model the feedback that the application is giving to the user in this situation.
In these cases, we _could_ use the controller to hand this feedback to the view (tighter coupling), but this tighter coupling might entangle the view with the controller more than is desirable. It makes better sense to have this feedback live in the model somehow, and have the view get this feedback when it queries the model.
I have been intrigued by the possibilities of what I now know is called the Transform View pattern (http://www.phpwact.org/pattern/transform_view). The model produces a representation of itself, which the view then transforms into a form that is appropriate for that context. XSLT is the likely choice of language for this type of situation. A couple of things are intriguing about this pattern:
- Different views can be constructed for different contexts, without changing or duplicating anything else about the underlying application. This makes it much faster and easier, for instance, to create a mobile web app for different platforms, once the initial application is complete.
- In the case of web programming, some or all of the transformation can be pushed to the client (browser), because all of the modern browsers are XSLT capable.
My inclination at this point would be to build up the application as an XML representation of the model, use CSS for as much as possible, and do the minimal XSLT transformation that is needed to deal with presentational realities. Do XSLT on the browser when possible, on the server when necessary. This workflow maximizes the agility of the application itself and the ability to create new outputs for new contexts as they come up.
That brings us to the controller, which is the part of this that I struggle with the most.
A controller is the means by which the user interacts with the application. A controller accepts input from the user and instructs the model and viewport to perform actions based on that input. In effect, the controller is responsible for mapping end-user action to application response. For example, if the user clicks the mouse button or chooses a menu item, the controller is responsible for determining how the application should respond. — http://ootips.org/mvc-pattern.html
In a web application, if the user submits a GET request, the controller will simply hand the request to an appropriate view.
If the request is a POST, PUT, or DELETE, however, the controller’s job is to submit that data to the model, receive the model’s response, and then call the view to get the model’s status. The controller is not necessarily to pass data or messages directly to the view (although it is often used to do this, such as in Ruby on Rails). It seems that, for decoupling, it makes better sense for the controller simply to tell the model to update itself, and then notify the view that the data has been updated, without acting as a courier. The view is then able to get whatever it needs from the model directly.
In Ajax apps, it would seem that the view is updating the model directly, but what’s really happening is that it is posting changes to the the controller and mirroring those changes directly, or it is querying the controller to return another view or partial view, which is used to modify the current view.
The controller, then, becomes a fairly simple routing mechanism. If the request is a POST or other data modifying request, it simply passes that to the model, which processes it and returns. (This processing can be set up to be asynchronous where necessary.) After passing the request to the model, the controller notifies the view, which can then query the model for the updates (if its an asynchronous application, the view can start polling the model to wait for updates. This is potentially where the Observer pattern, below, becomes useful).
The controller also putatively has the job of doing authentication (authn) / authorization (authz). In fact, that’s a major purpose, because the outcome authn & authz will determine exactly what is done in relation to models and views (e.g., a controller won’t POST to the model if that post is unauthorized, and will provide a view that indicates as much).
Still, I see a need to keep the controller very specifically to its limited job of routing requests and posting/putting/deleting to models. This is a very different way of thinking about the controller from what is currently being done in, say, Ruby on Rails.
It looks like what I have in mind is the Front Controller pattern: http://www.phpwact.org/pattern/front_controller
A completely different approach is called the Page Controller pattern: http://www.phpwact.org/pattern/page_controller
In the Page Controller pattern, routing passes transparently to template files, which are also the “views,” which then process everything about the request. The advantage is simplicity and immediacy. The disadvantages are (1) strong coupling between the URL space and the template space (solvable by adding a routing layer); (2) strong coupling between control logic and presentation; and (3) the potential for duplication of control code in the presentation layer. Thus it does make sense for the controller to be a bit more than a completely transparent layer passing requests directly to templates/scripts at URLs.
An observer is an entity that creates a mechanism for an *active model*, in which views / controllers can register to be notified whenever a model changes, so as to be able to respond to those changes.
Requests are initially handled by the Front Controller, which does authn & authz, passes legit POST/PUT/DELETE requests to the appropriate model, and then routes requests to the appropriate view. Also hands request and session data to the view, since it would be redundant to get this info from the database more than once. Use a dictionary to map requests to models and views.
Views receive requests from controller, deal with session data, and interact with the model to produce a presentation of the model to the client.
Models provide all the data and the logic required to manipulate that data. They also provide representations of the data based on the context. For example, at a bare minimum a model class should know how to produce XML of a record or set of records. It probably also knows how to produce an HTML representation of itself, and an HTML form representation of itself, but these things are less necessary because they can both be derived from the XML representation by the view, depending on the context.
Observers can be used to send notifications to views, which pick up these notifications and use them. Doing this in a webserver context requires some sort of storage of notifications for views to access, because of the asynchronous, event-driven nature of the interface.