Binding Dependencies

4

Category : binding, binding dependency, Flex, parsley, presentation model

A common problem I’ve run into, even on the SDK team, was when you have one property dependent on another property (or a set of other properties), and you need that property to be Bindable. For example, in spark.components.VideoPlayer, volume is dependent on the videoDisplay.volume property. Usually to make such a property bindable, you add an event listener to know when your dependent property changes. In this case, if you check out VideoPlayer.partAdded(), you can see code like that. However, when I started using the presentation model pattern, this issue seemed to keep coming up quite frequently.

Let’s take a simple example where someone is placing an order. If that person has a billing address and a shipping address in California, we need to show them some extra questions because of extra regulations in California.

Our made up model looks like:

public class Order { 
 
    [Bindable]
    public var billingState:String;
 
    [Bindable]
    public var shippingState:String;
 
}

And in the View, we want to do something like:

<s:Form>
    <s:FormItem label="Billing State">
        <s:DropDownList selectedItem="@{ presentationModel.order.billingState }">
            <s:ArrayList>
                <fx:String>AL</fx:String>
                <fx:String>AS</fx:String>
                <fx:String>AZ</fx:String>
                <fx:String>AR</fx:String>
                <fx:String>CA</fx:String>
                <fx:String>CO</fx:String>
                <fx:String>CT</fx:String>
                <fx:String>DE</fx:String>
            </s:ArrayList>
        </s:DropDownList>
    </s:FormItem>
 
    <s:FormItem label="Shipping State">
        <s:DropDownList selectedItem="@{ presentationModel.order.shippingState }">
            <s:ArrayList>
                <fx:String>AL</fx:String>
                <fx:String>AS</fx:String>
                <fx:String>AZ</fx:String>
                <fx:String>AR</fx:String>
                <fx:String>CA</fx:String>
                <fx:String>CO</fx:String>
                <fx:String>CT</fx:String>
                <fx:String>DE</fx:String>
            </s:ArrayList>
        </s:DropDownList>
    </s:FormItem>
 
    <s:FormItem label="California Question1"
                includeInLayout="{ presentationModel.order.shippingState == 'CA' &amp;&amp; presentationModel.order.billingState == 'CA' }"
                visible="{ presentationModel.order.shippingState == 'CA' &amp;&amp; presentationModel.order.billingState == 'CA' }">
        <s:TextInput />
    </s:FormItem>
 
    <s:FormItem label="California Question2"
                includeInLayout="{ presentationModel.order.shippingState == 'CA' &amp;&amp; presentationModel.order.billingState == 'CA' }"
                visible="{ presentationModel.order.shippingState == 'CA' &amp;&amp; presentationModel.order.billingState == 'CA' }">
        <s:TextInput />
    </s:FormItem>
</s:Form>

Now the same code: presentationModel.order.shippingState == ‘CA’ &amp;&amp; presentationModel.order.billingState == ‘CA’ is repeated 4 times, the ampersands have to be escaped, and overall it’s just quite ugly. Now, one of the neat tricks I’ve learned is that you can spruce it up by doing something like:

<fx:Declarations>
    <fx:Boolean id="showCaliforniaQuestions"> {presentationModel.order.shippingState == "CA" &amp;&amp; presentationModel.order.billingState == "CA"} </fx:Boolean>
</fx:Declarations>
 
...
 
<s:FormItem label="California Question1" includeInLayout="{ showCaliforniaQuestions }" visible="{ showCaliforniaQuestions }">
    <s:TextInput /> 
</s:FormItem>
<s:FormItem label="California Question2" includeInLayout="{ showCaliforniaQuestions }" visible="{ showCaliforniaQuestions }">
    <s:TextInput /> 
</s:FormItem>

That definitely works and is much cleaner than before; however, that means we have some business logic in our View that is extremely hard to test. That logic should really be in the presentation model. If we try to move it into the Presentation Model, we’ll end up with something that looks like:

<s:FormItem label="California Question1" 
    includeInLayout="{ presentationModel.showCaliforniaQuestions }" 
    visible="{ presentationModel.showCaliforniaQuestions }">
    <s:TextInput /> 
</s:FormItem> 
<s:FormItem label="California Question2" 
    includeInLayout="{ presentationModel.showCaliforniaQuestions }" 
    visible="{ presentationModel.showCaliforniaQuestions }">
    <s:TextInput />
</s:FormItem>
public class MyPM {
    public function MyPM() {
        super();
    }
 
    [Bindable]
    public var order:Order = new Order();
 
    public function get showCaliforniaQuestions():Boolean 
    {
        return order.shippingState == "CA" && order.billingState == "CA";
    }
}

However, doing that doesn’t work. The reason is because showCaliforniaQuestions isn’t Bindable. Now, to make it Bindable, we need to add Bindable metadata on top, add event listeners (or use a ChangeWatcher) to let us know when the shipping state or the billing state changes, and dispatch a new binding event when we get notified that the shipping or billing state changes. This turns out to be quite a lot of extra, ugly code, which means most people just end up keeping this logic in the View because practically it’s just too much work and too ugly to move it to the Presentation Model. This is all fine, but this kept issue kept cropping up in practice, so I finally sat down to come up with a more palatable option.

One of the very cool things about Parsley is that you can add your own custom Metadata, and Parsley will help process it for you. Even though I’m really new to Parsley, it turns out that this is relatively easy to do. So I decided to go ahead and add some custom metadata to help deal with this. What’s really neat is that I added a Parsley processor for Bindable metadata. I added a new property on that metadata, which allows you to define binding dependencies–basically Bindings that are dependent on other properties. In our particular example, here’s what it looks like:

[Bindable(event="showCaliforniaQuestionsChanged",dependentProperty="order.shippingState")]
[Bindable(event="showCaliforniaQuestionsChanged",dependentProperty="order.billingState")]
public function get showCaliforniaQuestions():Boolean
{
    return order.shippingState == "CA" && order.billingState == "CA";
}

All we did was declare the showCaliforniaQuestions as Bindable, where that binding is dependent on the order.shippingState and order.billingState properties. The Parsley metadata processor will step in and handle everything else. I personally like this solution a lot as it piggy-backs off of the Flex SDK framework’s Bindable metadata and just extends it for our purpose. It’s easy to use and pushes our logic into Presentation Model, which makes our code cleaner and more importantly, testable.

The main downside to this approach is that we’re exposed to spelling mistakes or later refactorings since the dependentProperty in the Bindable metadata is not checked by the compiler. Ideally, this would be something we could add to the ActionScript compiler so that it could inspect the getter and pick out all the bindable variables. However, we don’t have that, and I find this pattern really convinient for me. The code for all of this can be found in the attached Flash Builder project — feel free to use it.

Why Presentation Models can be confusing

7

Category : Flex, presentation model

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:

Presentation Model Pattern Diagram

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: