Thursday, June 09, 2011

Why Presentation Models can be confusing

When I decided to leave Adobe and the Flex SDK team after almost 4 years, I left because I wanted to see what issues people were encountering with the SDK and to learn what some of the challenges are with application development. Well, one of the first things you're bound to encounter as an application developer working on a large application is some way to separate the logic of the View from the actual look of the View (as well as the actual business logic, but I won't talk about that here). There are lots of ways to achieve this separation, and I'm not going to debate which way is best to it However, I'm going to take a look at the Presentation Model pattern and go through some of the questions I had when I was trying to understand this pattern. Luckily for me, I have a lot of great co-workers, like Miguel Sanchez and Dan Johnson who helped me understand it.
Introduction:
The Presentation Model is a standard pattern where logic to control the state and behavior of the view is extracted from the view itself. Simply, the Presentation Model (PM) controls what the View displays--the View controls how to display that information. The PM coordinates with the domain layer to retrieve information and perform actions.
Goals:
The purpose of the Presentation Model pattern is to:
  • Separate out the state and behavior of the view from the presentation of the View itself
  • Provide a GUI agnostic, testable interface
  • Provide a consisten, performant pattern that developers can easily follow
Definitions:
View - A class defining the GUI for a particular part of the application. The View may be composed of other Views or other UI controls
Presentation Model (PM) - An abstraction of a particular View. It controls the state and logic for a particular View; however, it does not control how the View presents this information.
Domain Layer - A generic term for the business logic for a particular application. This may include domain models, commands, service layers, controllers, etc...
Overview:
View Responsibilities:
  • The View should contain very little logic--only GUI specific, layout implementation should be contained in the View
  • The View should use databinding to grab information from the Presentatio Model
  • The View should call methods directly into the PM (see FAQ for description of right level of abstraction)
  • The View should attach Flash event listeners on the PM to receive any event information (if using Parsley, the View should not communicate to anyone using Parsley messaging as configuring a display object in Parsley is a huge performance hit)
Presentation Model Responsibilities:
  • The PM should hold the logic, state, and data of the user interface. It is essentially an abstract, non-GUI dependent abstraction of a View
  • The PM controls what the View displays (how to display it is up to the View)
  • The View calls into the PM via public methods. The PM then takes those actions and talks to the Domain Layer.
  • For the PM to talk to the View, it should use properties with data-binding or Flash events.
FAQ (aka-Questions I had)
If the Presentation Model is tied 1:1 to a View, why create another class, when the View can contain that logic directly? The main purpose of the PM is to separate out what the View should display from how it should be displayed. The PM controls the state, behavior, and any business logic for the View. The View controls how to display the appropriate information. The point of the PM is not to be reusable in other Views. In order to foster code re-usability, put similar code into the Domain Layer or into the other PMs that can be used by your PM. As Martin Fowler says, "Presentation Model may interact with several domain objects, but Presentation Model is not a GUI friendly facade to a specific domain object. Instead, it is easier to consider Presentation Model as an abstract of the view that is not dependent on a specific GUI framework."
What is the right level of abstraction for the View and the PM to talk to each other? Here are some examples of how the View may talk to the PM:
  1. <s:Button id="submitButton" click="{ myPM.submitButton_clickHandler }" />
  2. <s:Button id="submitButton" click="myPM.onSubmitButton(busIdTI.text)" />
  3. <s:Button id="submitButton" click="myPM.setBusId(parseInt(busIdTI.text))" />
  4. <s:Button id="submitButton" click="myPM.unsubscribe(); myPM.setCurrentBus(new Bus(parseInt(busIdTI.text))); myPM.subscribe();" />
There is no right or wrong answer here, but in general, the approach should probably be #2, #3, or somewhere in between. Try to stay away from #4 where the View does too much work. Try to stay away from #1 where the PM now knows about the GUI concepts (a MouseEvent in this case).
If your View is displaying data in a grid, where should the column definitions for that grid go? The Presentation Model defines what the View display; however, the goal should be to do that in a GUI agnostic approach. Ideally, the PM should define what columns need to be displayed as Strings or Enums, but it wouldn't actually define DataGridColumn instances. In a practical world, this ideal separation doesn't always make sense and can introduce a lot of unnecessary "translation code" (code whose sole purpose is to take the abstract output from the PM and concert it into a GUI specific implementation); however, in almost all cases, that goal should be striven for as it makes the Presentation Model more testable.
What is the difference between a "View" and an ordinary UI control? A View is a UI control, but it is a special UI control that represents an abstract interface for your particular application. A View may contain other Views and other UI controls. In general, not all custom components or views need to have a Presentation Model, but if the view has a reasonable amount of state and behavior, then the code should be split up into a View and a separate, testable Presentation Model. In general, it's up to the developer to make this judgement call, but a lot can be said for the consistency of always having a Presentation Model, even if it doesn't do much.
Can a Presentation Model contain other Presentation Models? In general it can. There are two basic models for this (atleast that I know of--see http://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.html). In the Componentized Presentation Model, the View can contain other sub-Views. Those sub-Views have references to their own PM, but the main View's PM does not have direct references to the sub-Views' PM. In the Hierarchal Presentation Model pattern, the main PM contains references to the other PMs directly.
How does the Presentation Model get attached to the View? In Parsley, the top-level view creates a Parsley context. This parsley context instantiates the Presentation Model needed for that View. The View has a FastInject tag to grab the Presentation Model. When using the Componentized Presentation Model (Views contain other sub-Views that need their own Presentation Model), the Parsley context also defines the sub-View PMs (either as a single instance if only one sub-View will be created or as a DynamicObject if multiple sub-Views are needed). To communicate with other Presentation Models, use Parsley messages. In the Hierarchical Presentation Model, the main Presentation Model would instantiate the sub-View presentation models directly and can be used to communicate with the sub-Views directly.
Conclusion:
It took me a while to understand why the Presentation Model pattern would be useful. In my first attempts at it, I kept making the "Presentation Model" more of a wrapper for a Domain Model object--something that could be re-used in multiple Views. Though having an object like that is useful--that is not the Presentation Model. The Presentation Model is there to help separate out the look of the View from the state and behavior of the View.
In a lot of ways, this separation reminds me a lot of a SkinnableComponent vs. a Skin. However, there's a more explicit contract in Flex 4 around SkinnableComponents and Skins; there are a set number of supported and toolable ways that the SkinnableComponent and the Skin can talk to each other. Having a tight contract like that and tooling support can be really useful, and it might be useful for the Presentation Model pattern as well. However, more on that and other issues I've encountered at a later date. I'm still relatively new to Presentations Models, so comments are much appreciated.
References:

5 comments:

Florian Fesseler said...

-> I don't think you should use brackets here because you call methods direcly on the PM. Thus, the Flex compiler will create unnecessary data binding code ;-)

Ryan said...

@Florian, you are correct :-) The sample has been update. Thanks!

bkogut said...

"The View should use databinding to grab information from the View"

you meant from the PM, didn't you ?

Ryan said...

@bkogut, you are right. It's been fixed in the post. Thanks for pointing it out.

Markus said...

Thanks for your post. I've been using the Presentation Model within the Swiz framework; their documentation also has information on the PM and specifically how to use it within that framework:

http://swizframework.jira.com/wiki/display/SWIZ/Presentation+Model