slide framework and the zeitgeist
As I've recently started talking to people about Slide, it's becoming clear that none of the ideas are new. Here are some examples of that.
We used to call our Presentation Models "View Delegate", but I found that lots of people were using the same identical pattern and I recently changed it. The new name is a lot more descriptive (and more familiar to developers too).
A week or two ago, I was talking to Nigel Pegg and he mentioned that he had done a big refactor in a project he is working on, just before I blogged about Cascade. He had removed singletons and replaced them with a very similar cascade mechanism.
Several people have emailed me, or come to talk to me after my presentations, to say that they are also using global URI-based view state mechanisms. The implementations vary dramatically but the basic idea, of using a URI for a state hierarchy in order to decouple knowledge of views from controllers, is the same.
Richard Leggett (also one of the people using global view state URI's), reminded me that our IAppProps interface is actually an Application Context. Other platforms use the same idea but under a different (better) name.
Overall, I'm very happy that we are making Slide open source. This sort of feedback validates our approach and gives me confidence that Slide will be useful and relevant to other people, and that I'm not on some wacky tangent from reality. But, even better than that, this feedback is already helping us to improve what we have. Whether it's better naming suggestions or, maybe in the future, insights into better implementations, we really can't lose out.
presenting at london flash platform user group
Johannes Nel and myself will be presenting tonight at the London Flash Platform User Group. I will be giving a version of the talk I gave last week in Sydney, about our Flex application framework, Slide. Johannes will be talking about some of our recent experiences with working with large data sets.
Slide framework preview part 2: cascading properties
Slide is view-oriented. Along with the view state management, it recognises that Flex apps are often modular and that these discrete pieces are mostly MXML components.
The Slide framework evolved from a set of classes that we were using over and over. And as we used them we realised that references to things like the StateManager were needed by every view, but using a Singleton was not the best solution. Firstly, a Singleton StateManager would make it impossible to write reliable unit tests against our views (since the StateManager is, by definition, stateful you couldn't assume that previous tests didn't have a permanent effect on it). Secondly, if we wanted to have separate autonomous pieces in the application, they'd still be tied to the same StateManager instance and would have to be in the same state as each other.
For maximum flexibility, we wanted to be able to set properties on a view and have all child views be able to access that property, but still be able to override it for themselves and their own children. To do this, we added a special metadata tag, [Cascade], which we use to annotate properties on views, which means that the value for that property cascades from wherever it is set to all the children. For example, a reporting application might have a view structure like this:
You can choose between viewing a report or looking at your report history. A report has a summary and a chart. The report history just shows the summary for each report and uses the same Summary component that is used in the report itself. Each of the components in the tree has a binding to currentReport and uses different information from it.
When the report changes, you would have some code that does something like:
mainView.currentReport = theReport;
And, for each view, you would have the following line of code (or, more likely, you'd put this in the base class that is used by all views):
[Cascade]
[Bindable]
public var currentReport:ReportModel;
And now all the views will now have access to that report. But then all the items in the History View will be the same. So the ReportHistoryView can override this property for each of it's children. Perhaps something like this:
<mx:Repeater id="historyRepeater"
dataProvider="{reportHistory}"
>
<ReportSummary
currentReport="{historyRepeater.currentItem}"
/>
</mx:Repeater>
This example is a little contrived, as ReportSummary would probably just have a normal attribute to set the report it needs to display, which you'd set from the parent component. But when you are dealing with many complex components that all need to be configured with many properties, you quickly start making savings in the amount of code you have to write, in particular in the amount of very similar code that you have to write. You only have to configure them individually if they are different from the parent.
Slide framework preview part 1: hierarchical view states
The cornerstone of the Slide framework is view state management. Typically, if you have code in a controller, that needs to make a change to the view - for example to change the index of a ViewStack - the controller will need access to that view. In Cairngorm, "commands" work like controller delegates, and get a reference to the view that triggered it; or they can affect view states by setting bindable flags on the ModelLocator, or use ViewLocator (deprecated) to update the view directly. Slide removes the need for controller type logic from needing access to views by having views respond to changes in global application view state.
Slide differentiates between two different kinds of view state changes; data and navigational. Data here means changes to the models that a view is bound to. They could cause a Repeater to update, a Label to change its text or a RadioButton to change its selected state. Navigation refers to larger changes where you move from one functional part of the application to another. The former is handled in Cairngorm quite well, and Slide does it in a similar way. But if you want to navigate around your application, it's a bit clumsy to control that with properties on the ModelLocator, and putting too much knowledge of view structure inside controllers can get messy quickly. I imagine this is part of the reason that ViewLocator is deprecated in Cairngorm now.
By comparison, in a classical JSP or RoR application, views are HTML-based templates with bindings. Controllers update the models and then send the populated template back to the browser, but they don't need to know anything about how that template is structured. That makes a page-based HTML application very straightforward to implement in clean MVC. In a typical "Ajax" application, this gets muddier because the controller is on the server but controller-type decisions are being made on the client too. This extra decision-making tier on the client must know a lot about the structure of the views in order to do it's job.
In a Flex application, you have the same problem with the client-side controller. Bindings take care of data-oriented state changes but often, to get to a particular "screen", you have to update several parts of the display tree.
Slide uses URI's to represent a navigational state of an application. This lets you think about your application controllers in a similar way to how you would in the classical JSP/RoR application. When you make a decision in the controller, you can update the application's view state URI, which is similar to redirecting to a URL, except of course without a page refresh.
For example, a Slide-based shopping cart might have the following view state URI's defined:
/MyShop/browse/MyShop/cart/MyShop/cart/checkout/MyShop/cart/checkout/complete/MyShop/cart/checkout/failed
From your controller's perspective, in moving between the steps, all it needs to do is:
stateManager.stateURI = "/MyShop/cart/checkout";
All views in your application have the opportunity to respond to this state change and update themselves. The framework automatically maps changes to the view state URI to Flex states, if the view has defined one.
So the main MXML file in the application might have states defined like this:<mx:states>
<slide:ViewState name="browse" uri="/MyShop/browse">
<mx:SetProperty target="myViewStack"
name="selectedChild"
value="{browseView}" />
</slide:ViewState>
<slide:ViewState name="cart" uri="/MyShop/cart">
<mx:SetProperty target="myViewStack"
name="selectedChild"
value="{cartView}" />
</slide:ViewState>
</mx:states>
Note that, this view hasn't defined the checkout states, but these are child states of cart, so it will automatically go into the cart state.
In the above case, the states match up with the display tree structure. But suppose there is a footer in the application that needs to show contextual advertisements as your browse through products, shipping options when viewing the cart, and a legal disclaimer once you are at the checkout. The footer component might define states like this:
<mx:states>
<slide:ViewState name="browse" uri="/MyShop/browse">
<!-- Show contextual adds in this state -->
</slide:ViewState>
<slide:ViewState name="cart" uri="/MyShop/cart">
<!-- Show shipping options in this state -->
</slide:ViewState>
<slide:ViewState name="cart" uri="/MyShop/checkout">
<!-- Show legal disclaimers in this state -->
</slide:ViewState>
</mx:states>
As an application grows in complexity, managing states like this becomes increasingly valuable to keep navigational logic clear and simple.
The URI hierarchy is independent of the display list hierarchy. Views anywhere in the display list may react and update themselves based on any view state change. This allows you to be extremely flexible with how views are structured, without affecting controller logic.
The other huge benefit we have got from managing states this way is in the design phase. From an early point, we try to define the different view states and match up visual designs with URI's. This means we can build simple HTML click-throughs of the application to demonstrate the flow, and easily compare what we have built with what was designed.
introducing the Slide framework for Flex at WebDU
In June, I'll be presenting at WebDU in Sydney about Slide, our application framework, which will go open-source about the same time.
Slide is mostly about managing views and application states, but also about how different parts of an application get access to things like models and controllers. Over the coming weeks, prior to WebDU, I'll be posting about some of the ideas behind Slide and hopefully prompt some discussion.
At Memorphic we've been using the principals behind Slide for more than a year, and gradually combining the ideas into a framework that can be easily re-used distributed. It's been used in production sites for the likes of Fidelity Investments, Airbus and LMG (Nectar Loyalty Program) for both public and internal applications.
What we came up with is a library of classes that do a lot of work for you and encourage you to work in a certain way. However, you can just as easily take the parts that you want, and continue to build the majority of your app using the framework you are used to, such as Cairngorm or PureMVC.
new as3-xpath build 0.2.4 released
We just released a new build of the XPath library. It's just a couple of small bugfixes, and tweaks, but if you are using it already, you might like to update to the latest 0.2.4 release.
mxml syntax proposal for styles and events
Don't you think it's a bit funky that you set styles in exactly the same way that you set a property in MXML? And isn't it a bit confusing that you add an event listener in exactly the same way too? Actually, it's not that confusing. It's pretty cool and works quite nicely - I couldn't really see a better way. Except, I'd like to tweak it a little bit...
The first problem is, you can't have a style or an event named the same as a public property, if the object is going to be used in MXML. The other problem is that, when you look at some MXML code, and you see various attributes being set, you can't immediately tell if it's setting a property, listening for an event or setting a style. Events listeners are nearly always added in-line, and there are quite a few cases where it is better practice to use in-line styles instead of CSS (ask me after class). So, all in all, it's not a rare consideration. A third problem isn't so important to you and me, but the developers who create MXML editors would be able to simplify some of their code if they could depend on a namespace instead of having to figure out if a given attribute represents a property, style or event.
My suggestion is a very small change to what we have already. Adobe should simply define a namespace for events and another for styles. The Flex compiler does something completely different with each of these, so the namespaces should help Adobe to simplify their own code too.
Here's an example of what it might look like:
<mx:VBox style:verticalGap="3">
<mx:Button event:click="onClick(event)" />
</mx:VBox>
The extra namespaces would have to be declared at the top of every MXML file that used them, but that is not a big deal if that is mostly generated by a decent editor.
I made a bug report for this a while back, but never thought about it again. So feel welcome to vote for it if you agree that it's a good idea. Also on the report, I suggested how the same feature could be extended to allow some interesting custom extensions to MXML, by handling attributes in custom namespaces.
