I’ve been reading up about Model View Controller, Model View Presenter, Model View ViewModel, and so on, and generally, the underlying concept seems pretty simple to understand: keep the pretty visuals and sciencey guts as separate and ignorant of each other as possible. No getting the logic peanut butter in the design chocolate; cool, I like that.
The problem is I’m still a bit fuzzy as to that third part… the not-model-or-view one. Everyone seems to have their own idea of what to call it, what it should do, what’s proper, what’s just plain wrong… and I’m going nuts trying to figure out when a Presenter becomes a ViewModel and when a View shouldn’t be doing that because that’s the Presenter’s job and–
I’m rambling.
Rather than asking for someone to explain the difference between them–because that’s already been done time and time again (I know; I’ve read more articles than I can count)–I’d be curious to hear the thoughts of a few programmers on the model I’ve cobbled together myself.
That said, what would you classify this design as, and perhaps more importantly, do you see anything about this that obviously sucks? Sure, I’d love to hear I’m doing good if this truly is solid design, but I’d much rather be given solid advice over praise.
Note: I’ll be using “the Bridge” for the mysterious third part of Model-View-? to avoid any subconscious suggestions of what it “should” be.
Model
- Is the authority on data.
- Receives information about requested changes from the Bridge.
- Contains and performs all logic for how data relates to other data.
Informs the Bridge when data changes (for data the Bridge has expressed interest in).Wording edit: Allows outside subscribers (about which it knows nothing) to monitor it’s state or calculation results.- Has zero knowledge of the View.
View
- Is concerned with providing the user a way to view and manipulate data.
- Receives information about data updates from the Bridge.
- Contains and performs all logic for how to present data and controls to the user.
- Informs the Bridge when the user has performed an action that (possibly) affects the Model.
- Informs the Bridge what information it’s interested in.
- Has zero knowledge of the Model.
Bridge
- Is the coordinator and translator between the Model and the View.
- Makes any appropriate formatting changes to information being passed between the Model and the View.
- Retains information on “who needs to know what”.
- Has knowledge of both the Model and the View.
Additional Notes
- In more complicated programs, it’s common for there to be multiple Models. In this situation, the Bridge typically takes on the job of coordinating/translating between the multiple Models, and thus becomes the authority on what protocall/API/design Models should be built to. (e.g. if building a card game program, and you want to build an alternate deck shuffling model, you should use the Bridge for determining what functions are required for properly communication with the Bridge.)
- In small simple programs with only one View and Model, it’s common for the Bridge to “assume” what functionality is available on either side. However, as programs become more complex, it’s recommended that the View(s) and Model(s) report their functionality to the Bridge so that it can avoid inefficiencies and buggy assumptions.
I think that just about covers it. By all means, I welcome any questions you might have about the design I tend to use, and I likewise encourage any suggestions.
And as always, thank you for your time.
1
Your phrase
“Is the coordinator and translator between the Model and the View.”
indicates that your Bridge is the Presenter in an MVP architecture.
MVP and MVC are very similar, except that in MVP only the Presenter observes the Model while in MVC the View is also allowed to directly observe the Model (without the Presenter as a “Bridge”).
Your Model responsibility
“Informs the Bridge when data changes (for data the Bridge has expressed interest in).”
is perhaps poorly phrased or perhaps a mistake: you don’t want the Model to have a dependency on either the Bridge/Presenter/Controller or the View. Instead, you use either an Observer pattern, Events, or Reactive Programming to allow the Bridge to subscribe to changes in the Model. And then you can rephrase your responsibility as:
“Allows outside subscribers (about which it knows nothing) to monitor it’s state or calculation results.”
If your Model has no dependencies on your Controller or View, it is easier to test and vastly more portable.
4
I suspect one of the things that’s confusing you is that there are two entirely different patterns that are both commonly called model-view-controller.
There’s the original, as implemented in smalltalk and which is useful for local gui systems, and theres what I tend to think of as web-mvc, which swaps around some of the responsibilities of views and controllers so that controllers can sit on the server with views being on the client (perhaps as rendered html, or maybe via ajax).
Your description sounds to me like it would sit within most definitions of web-mvc.
2
There is a lot of discussion in the programming community about this exact nomenclature. No one seems to agree about much of anything.
For me, how the bridge is wired to the view mostly determines the name.
- If there can be a collection of views per bridge, then the bridge is a controller.
- If there is always one view per bridge, then the bridge is a presenter.
- If there can be a collection of bridges per view, then the bridge is a view model.
Sometimes things are not so clear cut. For example, a presenter could be connected to a composite view made of multiple subviews or a controller could be created without any knowledge of its views. Despite this, I think my rules are a good start.
As a side note, I like to pair down the responsibilities like this:
Model
Primary Responsibility: Persist data
Secondary Roles: Validate updates, notify observers of updates
View
Primary Responsibility: Present data
Secondary Roles: Accept input, present UX
Bridge
Primary Responsibility: Update data
Secondary Roles: Clean input, sync data and views
While your suggested pattern seems correct on the surface, and will undoubtably work for small instances, as your app becomes more complex, you’ll face problems where you’re unsure about what updates what, who listens to where, and why am I attempting to control so many Models from within so many Views, all of who need access to eachother, etc.
I recommend extending your ideas using the following pattern (taken from Amy Palamountain’s talk Enemy of the State):
Models
- Sync state with the data store
- Handle validation of new/updated data
- Raise events when they change state
Views
- Render templates
- Handle Model events
- Handle DOM events
- Mediates the interaction between Model and DOM
Controllers
- Manages at most a couple of Models & Views
- Keeps track of Views within a container
Modules
- The logical grouping of a Controller and its Views & Models
- Testable
- Small and maintainable (Single Responsibility)
- Coordinates (via the Controller) the state and events of the Views & Models it contains
- Free to present its own Views
- Not free to choose where to present its Views
Layout Manager
- Responsible for layout composition
- Defines an application shell in the DOM with areas that Modules can present their content
Dispatcher
- Listens to Events (via global PubSub stream)
- Responsible for loading new Modules based on Events
- Hands off loaded Modules to the Layout Manager
- Manages entire Module lifetime (creation, clean up, cacheing, etc)
- Event examples:
- Route changes (including initial load route)
- User Interaction
- Module event bubbled from a Model event due to server-side state change, etc
Application
- Responsible for overall setup, Instantiates things like:
- Dispatcher
- Router
- PubSub stream
- Loggers
- etc
This kind of pattern allows your application to be composable, unit tested, removes the complexity a Bridge would build up over time, keeps concerns separated nicely, etc.
As Amy points out: Be careful not to build a server on the client. And be careful not to fall into the doctrine of “I am making an MV* framework, therefore I must ___!” Instead, take all these ideas (and the other answers here), and find what works best for your application and team.
I highly recommend watching Amy Palamountain’s talk Enemy of the State (from which these ideas came), or at least to look over the slides from the talk.