Sunday, 18 January 2009

MVC / MVP in RIA programming

I have been working on an application where Flex is being used as a front end for a Java middle tier and Oracle database back end. In theory, the Flex code is all about the user interface / experience. The Java code is dealing with the business logic. So where does MVC come into this environment?

The bulk of our commands are designed to initiate service requests to the middle tier. In effect, they build our model. Our model primarily reflects the business model represented in the underlying database although extended to make it easier to perform some of the interface interactions. Does this mean that MVC in this context is the distribution across the layers or there a place for MVC or MVP in the rich internet application (RIA)?

As my thinking has clarified, I have become more convinced that MVP has its place in the user interface layer of the RIA. I see code where the user gesture has been captured and the view updated without going to the model. In some cases, there were resulting problems because of the tight coupling. In one such case, the simple solution was to create a command that updated the model within the RIA and then allow the view to update through the data binding mechanisms.

This isn't a sudden realisation that maybe we should have been writing our code this way all the time. My first piece of Flex code using the Cairngorm framework operated this way. I didn't have a middle tier or a back end. I simply had the memory based model that I was updating as user gestures required. Each user gesture cause a command to be activated which updated the model and the resulting changes where reflected in the view through data binding.

My view simply comprised an MXML file with a very small amount of ActionScript. That has changed with my current work in that the view comprises an ActionScript class (the mediator) that inherits the base MXML component used to build the view, and an MXML class that inherits the ActionScript class. This means that the MXML has full access to all of the public and protected variables and methods of the ActionScript class. In my coding, I have ensured that the ActionScript class knows nothing of the MXML component. This approach leads to easier unit testing. The MXML component only contains ActionScript within the property settings of the components added to the component container. We do use renderers, formatters, and validators but the basic principle is tht these can be tested independently of the MXML component. The MXML mediator acts as a staging area to gather together the various data required to complete the major user interface action.

Each user interface action is carried out through a command. In some cases, this might involve a series of commands that initiate service requests to the middle tier but the command or commands could simply initiate updates to the internal model. These changes are reflected back to the MXML through data binding.
The model is both the domain model and a presentation model. In some cases, the presentation model inherits a domain object and extends it to achieve the requirements of the interaction. In effect the model represents the current state of the interaction.

An example of how this structure impacts coding is the implementation of a select all check box. Each row on the data grid has a check box but some are disabled because of the status in the underlying model. The header has a check box that can be used to select all enabled rows in the data grid (more correctly the eligible data objects in the underlying model.

The original implementation attempted to mange this selection and tracking of status in the renders for the header check box and the row item check boxes. It appeared to work until a different sort order was chosen and then the selected check boxes no longer corresponded to the rows that should have been selected.

My solution was to have the underlying model remember what was selected or not selected. This included the status of the select all check box. When the select all check box is selected, it fires off a command that updates the underlying model. Data binding looks after updating the view and ensures that the correct check boxes are selected.

The core class to achieve the select all is below. There is a comment where the dispatch of the command should occur.

import flash.events.MouseEvent;

import mx.controls.CheckBox;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.events.DataGridEvent;

public class CheckBoxHeaderRenderer extends CheckBox
{
public function CheckBoxHeaderRenderer()
{
super();
}

private var _data:DataGridColumn;

override public function get data():Object
{
return _data;
}

override public function set data(value:Object):void
{
_data = value as DataGridColumn;
DataGrid(listData.owner).addEventListener(DataGridEvent.HEADER_RELEASE, sortEventHandler);
selected = ApplicationVariables.isSelected;
}

private function sortEventHandler(event:DataGridEvent):void
{
if (event.itemRenderer == this)
event.preventDefault();
}

override protected function clickHandler(event:MouseEvent):void
{
super.clickHandler(event);
// Dispatch of event to initiate command to update model
DataGrid(listData.owner).invalidateList();
}

}

We haven't been consistent in this implementation and it shows in the difficulty of maintaining some of the code. The solution to the select all check box problem can be applied to other problems where one component has to be updated because of an event caused by another component.

As I reflected on this solution, I thought of the idea of a metaphor promoted by the extreme programming community. The metaphor provides a framework for thinking about solutions to the particular application problem. The more that I think about Flex coding, I am thinking of it as a series of commands initiated by events. Sometimes the series of commands might be initiated by a particular user gesture or may a gesture simply fires one command.

No comments: