by Samuel Asher Rivello
Uncle Ben Parker of Spider-Man fame once said, "With great power comes great responsibility." We all want great power when developing software, but the question is: Can we accept the responsibility? Or more specifically, should we use a framework for our Flash projects?
The Adobe Flash Platform is excellent for deploying rich experiences, including websites, games, and applications. Over the years, this lightweight, interactive runtime has become the ideal choice for expressive media-centric web software. More recently, it has expanded to the desktop as well with Adobe AIR. One of the major benefits of the Flash Platform is flexibility in the work environment. With Adobe Flex 3 and Flash CS4 Professional (as well as a growing set of third-party Flash development tools), developers have a powerful toolset to create and export content to SWF. With the requirements of a new project defined and the tool selected, developers next define an approach for how to develop the software — a development plan.
Like many of today's Flex developers, I am largely self-taught. I graduated from Flash, and I spend much of my time learning from books and blogs about programming languages such as Java and C++. I started developing games in Flash 4, with its rudimentary editor and the limited functionality of Flash Player 4.
With each new version of Flash, more and more became possible. Today's Adobe Flash Player 10 offers amazing capabilities in sound and graphics. Along the way, as Flash Player matured, I too matured as a developer.
Completing my projects on time as well as learning new skills was challenging. I have spent vast amounts of time learning about the Software Development Life Cycle (SDLC), software design patterns, user experience design (UXD), and more. With expanding knowledge, I found ways to complete my Flash work more quickly, more efficiently, and more cleanly, which enabled me to do more work with fewer headaches when I return to a project months later to make a change. More recently, I have been exploring frameworks — or the bones onto which you lay the flesh of your program — and I selected PureMVC as my framework of choice.
A framework is a collaborating set of design patterns. Design patterns are proven solutions to common programming problems. So a framework is a set of proven solutions that work together. You can think of it like a human body where the framework is the skeleton and your code is the flesh.
In a broad sense, we all use a framework when developing, even if we don't know it. This is similar to our relationship with food. We all have a diet (our daily food intake) even if we are not on a diet (food intake with specific guidelines and goals). When we go on a diet, we are not adding something new to our life; we are simply becoming more conscious of something we are already doing: eating. By acknowledging frameworks, we become more conscious of how we organize our code to accomplish a certain goal. We could argue that we already create a custom framework for every new project, a process we hopefully learn from and improve on each time, but rarely do our frameworks start on a drawing board with adequate forethought and vision. Instead, they often start with a small scope that grows organically based on the changing needs of each day's development tasks.
Custom frameworks are helpful because they enable us to jump right into coding so we can begin to see functional software quickly. They also give us the flexibility to implement the fastest solution to a given problem without any protocols or best practices getting in the way.
However, with the custom framework approach, we are re-inventing the wheel for each new project, which takes time and energy. In addition, when we return to that project after weeks or months, we have to relearn the framework to continue development. Also we likely do not have the time or expertise to design an adequately strong and flexible framework. This often results in poorly architected applications, which do not clearly separate the application properly. That's why using an existing (proven) framework can be so beneficial. Here we explore the benefits of applying a proven, established framework to our projects as well as the challenges of getting started.
Of the many custom frameworks that are available, one of the best is the PureMVC framework created by Cliff Hall. I was introduced to PureMVC about two years ago when I came across it on the author's blog. Its rising buzz among the community and great documentation inspired me to try it. PureMVC's power, ease of use, support, and popularity with my clients keep me hooked.
The primary goals of PureMVC are straightforward:
One major benefit of adopting a formal framework is the common vocabulary, design patterns, and development tasks all developers on your team will be adopting. This enables you to jump-start development and easily add and remove staff because it reduces the amount of required knowledge. This isn't unique to PureMVC, but it is the most attractive benefit of using an established, proven, off-the-shelf framework. Here are some specific PureMVC benefits:
Computer scientists widely agree that separating an application's code into distinct, interlocking areas helps each area perform and scale well. While the details of how to separate are debatable, for this discussion let's agree on three major areas: model, view, and controller. These terms leave many self-taught Flash developers scratching their head. Here's a quick overview: the model is your data (for example, arrays and custom classes), the view is what the user sees (for example, text fields) as well as what the user interacts with (for example, buttons), and the controller is the brain of the application that knows how the model changes when the view is clicked and how the view should update based on changes in the model. Many frameworks are based on MVC for Flash and Flex, including PureMVC.
In PureMVC's implementation of the classic MVC design metapattern, the application tiers are represented by three singletons (see Figure 1). A singleton is a class where only one instance may be created.
Figure 1. A conceptual diagram of the PureMVC framework.
A fourth singleton, the façade, simplifies development by providing a single interface for communications throughout the application.
Here's a rundown of each singleton:
Typically developers do not interact with the singletons directly. Instead they use the façade and other core actor classes (such as mediators, commands, and proxies). The actor classes together with the UI, data, and delegate compose the major subparts to the MVC in PureMVC (see Figure 2). This hides complexity from the developer and makes it easier to work with the framework. Power users, however, can open the hood for custom implementations.
Figure 2. The anatomy of PureMVC.
The two challenges of ramping up with PureMVC are setting up the files for your first project and learning to think in PureMVC. Once you learn these basics, you're on your way to becoming proficient.
When learning new techniques like PureMVC, I find I need only 1–3 hours to really wrap my mind around the major concepts. Once you spend a couple hours learning PureMVC, you'll be able to decide if it will work for you, and you'll be able to more actively participate in conversations and blogs on the subject.
To get started, choose a sample project from PureMVC.org (there are several) or start from scratch.
The first steps to create a PureMVC project are:
Figure 3. The basic file setup of a PureMVC project.
To start thinking in PureMVC, let's skip ahead in the development process and examine a complete application. In the interest of full disclosure, I have neglected some steps in the list above and the project below, but I have covered the major steps for this overview.
In this simple Hello World application, we will see how PureMVC framework concepts are applied (see Figure 4). The application consists of a Hello Google mx:Panel component containing an empty mx:TextArea component and a Load Message! mx:Button component. Clicking the button calls the server (www.google.com) and places the HTML contents of the Google home page in the TextArea.
Note: This elementary example is designed to be a simple way to communicate the PureMVC concepts rather than perform anything of real value.
Figure 4. Sample Hello Google application.
Let's take a look at the nuts and bolts of PureMVC starting after the application has rendered to the screen and is waiting for a user to click that button.
When the user clicks the MainUI class's load_button, a custom LOAD_BUTTON_CLICK event is broadcast from MainUI. In PureMVC the UI class can dispatch Flex events, custom events, or both. The MainUIMediator class listens for this custom event and any other events from the MainUI. MainUIMediator also contains methods to populate the components within MainUI if needed. The mediator will listen for the LOAD_BUTTON_CLICK event and translate that Flex event to a PureMVC notification name of ApplicationFacade.LOAD_MESSAGE.
All notifications are stored in one tidy spot as static string names on the ApplicationFacade. The mediator's translation from event to notification enables the UI to discern the significance or insignificance of its component events and the mediator to discern the significance of that event in the entire application (the business logic). Let me reiterate that the UI just knows a button was clicked, and the mediator knows that click means the application should load something. This is an example of the decoupling throughout PureMVC. UI and mediator concentrate on different roles, but they work together to make the application fully functional. The role of the mediator is to populate the UI and listen for UI events.
Notifications are the events of PureMVC. To distinguish between the two in this article, when I refer to events I'm talking about something a UI dispatches. I refer to all other situations as notifications. Notifications are observed and reacted to in two major ways: First, any actor can listen for notifications directly by adding the notification names of interest to the actor's array property called listNotifications. This can be used in any situation, but it is best for noncomplex occasions. The other way a notification is observed is to register the notification to a command within the ApplicationFacade. This means each time a notification is sent, a command is executed. Commands are created, run, and destroyed instantaneously. They do not persist. This makes them ideal to hold processes that are complex or repeated throughout the application.
Notifications mapped to commands can be used in any situation, but the best time to use them is for complex occasions. A given notification can be observed in either of these ways or both. Typically an application uses a combination of both styles of notification observance. I like to use notifications mapped to commands as the view updates the model and listened-for notifications as the model changes and is then reflected in the view. The details of this technique may seem difficult to understand, but be patient. Both ways are explained within this overview of the Hello Google application. Read it a couple times and let the ideas sink in. Notifications, together with commands, make up the controller portion of the PureMVC framework.
Here's a quick recap with our Hello Google example so far: the MainUIMediator listened to a MainUI event and has sent the ApplicationFacade.LOAD_MESSAGE, which is mapped by the ApplicationFacade to a LoadMessageCommand, which will execute immediately. This command is charged with loading the message, a task that will be carried out by the model.
The model, in short, is all the data of the application and anything needed to get, set, and load that data. The LoadMessageCommand accesses the MessageProxy, which holds the sole reference to the MessageVO. A VO, or value object, is the construct in PureMVC for holding data. A VO can be any data type you wish and can contain any properties you need. What sets a VO apart from a regular class is that a VO is just a data holder — it's not a class that does something. VOs typically do not have methods, just properties. In that way, VOs are dumb objects; they need other classes to help them function completely. Just like a mediator mediates the entire application's access to a UI, the proxy proxies the entire application from a VO. In this way, VOs and UIs are lighter weight, decoupled, and reusable.
Proxies come in two flavors: static and dynamic. A static proxy contains a VO that is defined solely on the client. Typically the developer defines this while authoring the code. Thus it is hard-coded. A good example is a simple navigation menu that doesn't need to change over the life of the application. The dynamic proxy must get some or all of its VO data from the server. In our application, we see that MessageProxy is a dynamic proxy because its MessageVO must be populated by calling the server. While it is acceptable in PureMVC for a proxy to call the server directly, the best practice is for a proxy to use a delegate designed to handle all calls to a given server. Here we use the MessageDelegate class to handle the call. This delegate's
loadMessage() method calls Google's home page and passes the result to the MessageProxy. The proxy then sets the server result into the MessageVO for storage and sends a notification on behalf of the MessageVO indicating that the model has changed.
This ApplicationFacade.LOAD_MESSAGE_COMPLETE notification is observed by the MainUIMediator, which can then update the MainUI. In this case, the MainUI's text field is updated to contain the MessageVO's message string from Google.
That's it — a thin but complete slice of PureMVC in action, from the user's interaction to the server and back to the user interface (see Figure 5). The number of seemingly tedious steps for a simple task may seem like overkill, but then again, this application is very simple. With a simple application, we don't fully appreciate the benefits of a rigid framework. I recommend trying PureMVC on a small application to get comfortable. Then when you use the framework professionally for your medium or large applications, you should quickly see the benefits to your team workflow and project quality during the first version's development.
Figure 5. The messaging flow through the ‘Hello Google’ application.
In the words of marketing guru John Colanzi, "Sometimes you have to take a step back before you can move forward." As developers mature and their skills increase on the long road to mastery, there are few opportunities to truly leap forward. These special moments are the result of taking calculated risks to step up their game. While using this framework admittedly has a learning curve, can initially increase development time, and requires discipline, you may find it well worth the effort. Evolving from creating custom, per-project frameworks to using the consistent, proven PureMVC framework is one such opportunity to leap forward.
Samuel Asher Rivello is the principal of Samuel Asher Rivello is the principal of Rivello Multimedia Consulting (RMC). RMC's Flash and Flex services include software architecture, consulting, development, and training. Sam has a decade of experience creating games and applications, and is currently traveling the globe to collaborate with top companies. Follow Sam on Twitter at @srivello.