Home  >  

Mate for Framework Beginners

Author photo
AddThis Social Bookmark Button

Over the next little while, I am going to be exploring some of the more popular Flex Frameworks, and getting into the nitty gritty of what you need to know to get started with them. I'm not going to be posting any high level diagrams or discuss things in a "general way"–there are plenty of places where you can get that kind of information. Instead, I'm going to focus on where my pain points are and what solutions I found (or didn't) to resolve them. This won't be a series, exactly, because it takes a significant amount of investment to explore a Framework and I can't commit to one a week. Instead, these will come as and when I get time.

My approach is to take an existing example file from my personal blog, Lazy Loading Tree. I've written before about some of the architectural decisions I made in this example, so I'm not going to talk to that, except about things that changed during refactoring. I chose this example because it was fairly small and lightweight, but faces the very issues Maté and other frameworks are intended to solve, primarily loading data asynchronously among different view components that may be nested at different levels. The idea behind this "series" is that I will be taking this same example and rewriting it for different frameworks to see what the strengths and weaknesses, differences and similarities are among them.

Another thing I did was to change the architecture to use Presentation Model, as Pete Mackie did in his Maté example. I did this so I could explore the pattern for myself, but I found his example useful to follow. In order to have easily digestible posts, I am going to tackle the code changes I used to refactor for Maté and the Presentation Model pattern next week.

I decided to start with Maté, because everyone says it has the best documentation. I've never used a framework before (outside of Maté training at 360|Flex), so I figured I could use all the help I could get. One of the issues I had with the Maté training and documentation is that it seemed very strong on examples, but rather shorter on how you'd decide for yourself which tags to use and how to use them. I'm hoping that my "absolute newbie's" viewpoint will be helpful for those, like me, who are new to frameworks in general and so need a bit more guidance.

Updated 5/17/2010. I asked for input from noted Maté experts, Laura Arguello and Thomas Burleson, and they were kind enough to provide their thoughts on this post. I've added their comments inline.

What is Maté for?

The best way I know how to describe it is that Maté handles instantiation of your data classes and wires them up to your views. If you've ever pushed a property into a view, not because that view needs it, but because one of its child views does, you have experienced the problem Maté is meant to solve. You can have as many levels of nested views as you want, and Maté store references to each view as it is instantiated and inject the data into each as needed.

How does it work?

The documentation will tell you that Maté is event driven, but what does that mean? How does Maté listen for those events and react to them?

Visual Components

When you add an EventMap to your Application file, that EventMap will be able to listen to all events for the root Application and bubbling events for all child UIComponents (views) that are added to Application. In particular, it listens to the ADDED event and then stores a reference to each component that is referenced in the EventMap so that you can address the component later in the generator property of an "action" tag.

Laura Arguello's comment:
That is not completely correct.

It doesn't listen to the ADDED event, it listens for the creationComplete event. That is configurable as needed though [using the InjectorSettings tag].

Since Maté is able to listen for bubbling events on the children, I can see I'll need to brush up on which native events bubble and which do not. One thing to make sure of when you dispatch your own events from a View component is that you make the event bubbling. Note that if your event has custom properties, you should override the clone method to copy those properties, otherwise the event will not arrive at the EventMap with its custom properties intact.

Thomas Burleson's comment:
Since EventMaps are the "entry" points to the application's business layer, a best practice is to only dispatch custom business events (bubbling = true) to the EventMaps. While normal Flex events may be used in the EventMaps, those events should be used for UI-level interactions and component couplings.

In this manner, your EventMaps ONLY handle business-level triggers.

Data Components

Maté really "wants" to instantiate all of the data components you'll need in your Flex application, and it provides two methods that allow you to do this:

  1. Use the name of the Class you want instantiated inside curly brackets inside the "generator" property of an "action" tag.
  2. Use the name of the Class you want to instantiated inside curly brackets inside the "generator" property of an ObjectBuilder tag

Ok, I've used the term "action tag" several times, so I probably should defne it. Maté has two main tags that can be placed at the root level of the EventMap–EventHandlers and Injectors. All the other tags in Maté (except EventMap and LocalEventMap) will be inside these tags. The set of tags inside each EventHandlers tag or Injectors tag are called an "actionList," or series of actions to execute in response to an event or when a view object is built, so I call the tags that are valid in an actionList "action" tags.

Technically, an ObjectBuilder is also an action tag, but the key difference is that this tag allows you to set constructor arguments on the instance that is being built. If you want your data class to be able to generate events that Maté can listen for, you need to use this tag and pass in {scope.dispatcher} as one of its arguments. This allows you to dispatch events directly on Maté. This can get a tad confusing if you also have bindable properties on your data object and you're using custom binding events, because binding listens explicitly to the instance that is bound to. So you have to be aware to use dispatchEvent() to dispatch custom binding events and Maté's dispatcher to dispatch events that you want to handle in an EventHandlers tag.

Structure of an action tag

I found the documentation on many of the action tags confusing, so I thought I'd share "action tag properties according to Amy."

generator: The value of this property should be either the full path to a Class or the Class name in curly brackets (if you've imported the definition for the class inside a Script tag). Maté will first check to see if it has one or more cached instances of that Class. If it does, it will do whatever the tag is for using those instances. If it does not have an instance, it will create one and use that new instance.

method: (MethodInvoker and InlineInvoker) For MethodInvoker, this is a method on the instance retrieved by the generator property. If you use InlineInvoker, this will either be a method that can be referenced without creating an instance. This will either be a static function or a function that is local to the EventMap.

arguments, constructorArguments: These are arguments to be passed into the method/constructor when the EventHandlers/Injectors tag executes the "action." It's important to realize that you're limited in what you can pass into the arguments–it has to be "in scope." The event tag will always be in scope within an EventHandlers tag, as will any property of the scope Object, such as scope.dispatcher. If the previous tag was a MethodInvoker or InlineInvoker, the return from that method, if any, will be in the lastReturn property, so you can use it in this tag as an argument.

source: When you're moving data from one place to another (PropertySetter PropertyInjector, DataCopier), you can use "source" as the source of that data. If you use a Class name in the source property, Mate will retrieve an instance of that Class from its cache. You can also an instance that is in scope (for instance one from lastReturn). You cannot use dot notation in the source property. If you need to access subproperties, use the dot notations in the sourceKey property. Each tag has its own way of specifying where the data winds up, so I'll deal with that separately.

sourceKey: If you need to access a property on the instance referenced in the source property of the action tag, use this to tell Maté how to find that property. This is where you can use dot notation. For instance, if you wanted to access the someObject.name in an instance of MyModel that Maté instantiated for you in a generator or ObjectBuilder, you would use {MyModel} in the source property and someObject.name in the sourceKey property.

targetKey: Once you specify what object is receiving the data (in whatever way makes sense for whatever tag you're using), use the targetKey to say what property on that object will receive the data. As with sourceKey, this is where you put any dot notation for the destination's subproperties.

That's not all of the properties that are available on all of the tags, but it should give you a good starting point for using most of them.

About moving data

I found three tags that will enable you to move data from an event to an object or from one object to another. They're all slightly different, so I thought I'd look at what each is for and how their usage differs.

PropertyInjector: The PropertyInjector tag is always used inside an Injectors tag. The PropertyInjector has no property to specify which object receives the data. Instead, the Injectors tag has a target property that retrieves all instances of that Class for use in the PropertyInjector tags inside. In case you don't need to inject the information into all instances, each PropertyInjector also has a targetID property that can be used to limit the injection to instances that have that id.

Laura's comment:
It doesn't "store" a reference to each component. The Injector actions are run immediate after the creationComplete event is received, and never again, and no instance is stored. The only one time you can access the view is when the Injectors are triggered. That view will not be available as a generator in the MethodInvoker, etc.

PropertySetter: The PropertySetter tag can be used anywhere, but I found it especially useful inside EventHandlers tags. The destination where the data is going is set with the generator property.

DataCopier: If you have an object that is already in scope (for example, one from a previous MethodInvoker call in lastReturn), then you can copy data to it with a DataCopier by specifying it as the destination property. You can also use DataCopier to copy data for later use within the same EventHandlers or Injectors tag, by using data as the value of the destination property.

Overall thoughts

Maté does a great job of accomplishing its purpose, and I especially like that the only place you'll find Maté code is in the EventMap. Otherwise, my code was completely spotless, with each class having its own concerns and not at all worried about how to get information to and from other parts of the program. Some developers have reported that they don't like debugging with Maté, but I think they have done a great job with the Debugger. I found the errors to be easily intelligble so that I could find and fix the problem without much of a fuss.

That being said, there were a number of things that made me pretty uncomfortable using Maté. Possibly some of those issues are just my inexperience with frameworks in general and this one in particular, but I found them worth mentioning.

  • A script block just for imports. A Maté EventMap is primarily MXML. But because it winds up binding to Class names and static constants, you have to have import statements pointing to every class you reference. This means a Script tag whose sole function is to facilitate these imports. You can "import" the classes by hand typing a mx:Class tag without code assistance, but this gives you no help with code hinting, and, since you have no code hinting, involves more typing than using the Script tag. I think this is a problem more with MXML than Maté, but it's a pain when you're using MXML in a way that's "out of the box" compared to what Adobe was apparently thinking when they decided how MXML was going to work.
  • Lack of type safety/code hinting. Since you're not using a variable of a specific type and your argument or key property is separated from the Class name, you get zero help from code hinting, and of course the compiler does not warn you if you have made a mistake. This burns up a lot of time looking back and forth between the EventMap and the documentation or code to make sure you've entered values of the right type in the right place. Mysteriously, even some parts of the Maté framework don't show up in code hinting in the EventMap, such as scope.dispatcher.
  • Over dependence on binding. Maté works most easily and most intuitively if you use binding, which can cause a significant performance hit. To some extent, you can mitigate this by dispatching your own binding events, but I found at least one place where this didn't seem to work. I'm not sure if it was my mistake or if something in Maté or Flex binding was specifically listening for "propertyChange," but I finally had to remove the custom event and the dispatchEvent call for that one property. A binding problem can be very difficult to debug even if you're not using Maté.
  • Difficulty of figuring out how to reference things. I think this is definitely my own inexperience with the framework, but I found it difficult to figure out how to get a handle on how to tell Maté which object I wanted operated on. In an application that's more complicated than my example, with multiple instances of the same Class that you needed to read from, I don't know how you would nail down exactly which one you wanted. Potentially you could create methods on your EventMap (or static functions elsewhere) to inspect objects and tell you whether to proceed or not, but that strikes me as very "unMaté."

Next week, I'll go over the code changes I made when I refactored the example for Maté, so stay tuned!

Read more from Amy Blankenship. Amy Blankenship's Atom feed

Comments

Leave a comment


Type the characters you see in the picture above.


Tag Cloud

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.