Devlico.Us
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @devlicious

Billy McCafferty



Considering a View's Get/Set Roles with MVP

[Update May 7, 2007:  Added sequence diagram, submitted by Yanic Inghelbrecht, to better explain "Use Update Method in lieu of Getter" technique.]

There are many ways to implement Model-View-Presenter; Supervising Controller and Passive View are just two implementation examples.  A question was asked on my overview of the subject as to whether or not a view's properties should have both setters and getters.  For example, consider an "add/edit customer" view.  This view first shows the available customer data, via a setter on the view, and then allows the user to update the information displayed.  Should the view have both a setter and a getter for the customer class?  (As I understand it, if you're using Passive View, this is a moot question as the view should not be intelligent enough to interpret and/or update the domain model directly.)  But if you're using Supervising Controller or another approach which allows the view to know about the domain model (or DTOs for the domain model) then this is a great question to discuss.  I'll list the (un)successful approaches I've used and pros/cons of each.  (Here, I use "entity" to mean any domain object that's stored within the DB.)

Return Ready-to-Save Entity from View via Getter
With NHibernate, if you have a ready-for-storage entity, you may simply call SaveOrUpdate on that object.  If a new entity is being created, then the view may need to work with factories and/or be aware of the business rules for creating a ready-to-save entity.  The internal consistency of that object can, obviously, be verified by the presenter or validation logic built into the domain object itself, but I never liked this approach as it gives the view a lot of responsibility for creating a new entity and creates a lot of untestable code.

If an existing entity is simply being updated and returned via the getter, the view must have a handle on the existing entity to update it.  Accordingly, the view can:

  1. Re-create the entity from scratch, set its ID accordingly, and return the ready-to-save object.  This approach is wrought with problems.  If the view gives the recreated object a wrong ID, you've now corrupted your data.  In my overview of NHibernate, I exposed ID as a publicly, settable property.  In my upcoming update to this article, I recommend not exposing the ID setter.  Only the ORM or entity-loader should be able to set this critical property.  As another drawback, if the entity keeps track of auditing information, such as DateCreated, this approach will overwrite it.  There are other drawbacks to this approach and it should be avoided.
  2. The view can talk to a DAO directly to get the existing entity, update it's properties, and return it to the view.  Although not as bug-prone as the previous suggestion, this now gives the view the responsibility of coordinating with the data-access layer directly.  This grays the line between the responsibilities of the view and the other layers of the application and adds non-trivial business logic to the view which is difficult to test.
  3. The view can be given a direct handle to the loaded entity by the presenter via another setter.  This seems a bit round-about and depends on a two-step process.  Additionally, the view now has two setters which may be confusing and difficult to maintain.

Return DTO from Getter
Instead of returning a fully ready-to-save object from the view, the view could, alternatively return a DTO consisting of only the appropriate information to be updated.  The presenter could, in turn, get the existing object from the DB (or create a new one), transfer the DTO information onto the persistent object, and save it back to the DB.  The primary benefit is that you can completely separate the view from knowing anything about the domain model while still being able to communicate more than one primitive at a time.  The major drawback is that DTOs now need to be maintained along with their domain model pairs.  So if you add a new, updateable property to the domain object, you'll then need to add the property to the DTO and then modify the DTO-to-domain-object transfer logic within the presenter.  (Alternatively, You could also add an UpdateWith(DTO) to the entity so that the transfer logic is more contained, but it still leads to further maintenance.)  But the bottom line is that this is a good approach if you really need to keep your views from having a direct dependency on the domain layer.  Because of this clean separation, this brings the added benefit of removing temptation for domain logic to bleed into views since the view is limited to communicating with the Presenters/DTO layer.  But again, it comes with a lot of additional maintenance to keep the DTOs synched with the domain model.

Use Update Method in lieu of Getter
A simpler approach that I'm having luck with is including a separate update method on the view and not having a getter for the entity.  Going back to the "add/edit customer" example, a "Customer { set; }" would be on the view interface to show the data, but not a getter.  The view interface would then also include a "void Update(Customer customer);" method.  Accordingly, the view would then accept a customer object from the presenter and update its properties from the view.  The communications would be as follows:

The above image was created and submitted by Yanic Inghelbrecht via Trace Modeler.  Thanks Yanic!

The sequence diagram is interpreted as follows:

  1. User clicks "Save Changes" button which invokes btnSaveChanged_OnClick in the code-behind.
  2. Code-behind calls presenter.SaveChangesTo(customerId).
  3. Presenter talks to the Customer DAO (or service layer) to get the loaded entity from the DB, using the ID passed to it from the view.  (If the ID was 0, then the Presenter creates a new entity via a constructor or factory.)
  4. Presenter calls view.Update(customerToBeSaved), passing the entity loaded from the DB.
  5. View updates the entity with values from a form.
  6. (Optionally, when appropriate) Presenter, or more appropriately, the domain layer via something like the Validation Application Block, verifies that the updated entity is internally valid.
  7. Presenter calls customerDao.SaveOrUpdate(customerToBeSaved).

With this approach, the view remains ignorant between whether a new entity is being created or an existing one is being updated.  Furthermore, separate DTOs aren't being maintained while still minimizing the responsibilities of the view.  As an added bonus, there's very little code that's not testable.  The drawback to this is that it gives the view direct access to the persisted objects and, thus, the domain layer itself.

A Place for View Getters
There are other scenarios in which getters on the view are valuable.  One such example is an IsDefaultView/IsPostBack getter so that the Presenter can determine if post-back-specific actions are necessary.  But in my own experiences, I usually pass contextual data, such as this, into the InitView, or other method, of the Presenter.  But at times, exposing a getter on the view can be simple and useful.

Recommendations
If your project (team) requires a very clean separation between the view and domain layer, then I recommend considering the "Return DTO from Getter" approach.  This keeps the view very contained while allowing you to be more efficient than passing around a ton of primitives.  But like CRUD stored procs, the DTOs require a lot of maintenance.  Alternatively, if you have a smaller and/or more experienced team, you can bypass the DTO layer altogether in favor of the "Use Update Method in lieu of Getter" approach.  This is simple, minimizes responsibilities of the view but, on the downside, allows the view to do more damage, so to speak.  But with proper encapsulation, the view's access to the domain layer can still be limited.  I've been developing/maintaining my current project for 1 1/2 years and have found the latter approach to be the most maintainable and simple.  But either way, both approaches lead to highly testable code.

Billy McCafferty


Published Mar 19 2007, 09:40 AM by Billy McCafferty
Filed under:

Comments

JoeyDotNet said:

Great Stuff!  Speaking as one who's dealt with the pain of maintaining DTO-to-Entity mapping, I can attest that it can definitely be overkill for fairly trivial CRUD apps.  I do usually prefer Passive View, but I really like your use of an update method on the view.

# March 20, 2007 9:17 AM

rajiv said:

Thanks for the reply! I posted a connected question in the code project forum.

# March 23, 2007 2:33 AM

Joey Chömpff said:

Hey great article. I'm using the Web Client Software Factory for some time now and this uses an ObjectContainerDatasource who redirects events (CUD) to the presenter.

# April 20, 2007 3:52 AM

Billy McCafferty said:

Joey,

Do you have any major complaints of WCSF at all?  I haven't tried it myself yet but want to give it a shot.

# April 20, 2007 12:54 PM

Joey Chömpff said:

No I don't have major complaints about it, but there aren't many examples on this framework. And I'm quite new at the IoC principle.

# April 25, 2007 7:27 AM

Doctor Deploys Blog :: Model View Presenter links said:

Pingback from  Doctor Deploys Blog  ::     Model View Presenter links

# November 6, 2007 1:52 PM

How loose is loose enough? « maonet technotes said:

Pingback from  How loose is loose enough? « maonet technotes

# November 6, 2007 10:27 PM

MVP (Model-View-Presenter) « Eppur si muove said:

Pingback from  MVP (Model-View-Presenter) « Eppur si muove

# November 28, 2007 8:26 AM

dave^2=-1 said:

Billy McCafferty has a nice post titled Considering a View's Get/Set Roles with MVP . Billy looks at

# February 1, 2008 5:54 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Proudly Partnered With