Close Window

Print Story

Event-Model Programming with Macromedia ColdFusion

If there's one word that summarizes the core of a successful software development project, it's organization. A lot has been written about the organization of documentation and organization of code, but not a lot has been written regarding the organization of the way code is executed.

We're going to take a look at one way to do exactly that using the concept of events to control how code is executed within an application. The term event should be fairly familiar to anyone who's used JavaScript with HTML (raise your hand if you haven't) and seen terms like onClick or onSubmit. Simply put, an event model is a way of organizing not the code, but the way that code is executed (or execution path - the order in which code is executed to respond to a particular request).

This method of organization often goes hand in hand with using frameworks like ModelGlue, Mach-II, or Fusebox. In each of these cases, events (Fusebox calls them fuseactions) are given arbitrary names and passed along on the URL or in a form post, each named event causing sections of code to be executed. As frameworks become a larger part of how we work, an in-depth examination of using events to organize and control execution within an app is important.

Event-Based Flow Control
In the case of Model-Glue, Fusebox, and Mach-II, the actions taken by the application when the user clicks a link are guided by an XML file based on parameters passed on the URL. Among other things, the XML file typically includes several sections that outline the flow of application logic for all actions the application may take (saving data, altering data, retrieving data for display, etc.). The various requirements for any given page can be provided by structuring your events from high-level (or will cause lots of different actions to be taken) to low-level (or very specific - it will only do one thing).

While the examples shown are using ModelGlue, the same structure can be applied to Fusebox and Mach-II. The terminology and a few of the specifics may change, but the ideas are applicable to any of the three big HTML-interface frameworks. If you aren't familiar with ModelGlue, head over to www.model-glue.com and download it. It includes a QuickStart Guide that covers how to use the whole XML file and how to use the framework to build applications. Because this article is intended to highlight the use of tiered event models to structure Web applications, a complete explanation of ModelGlue is beyond its scope.

We also need to give a few definitions before we get started:

Back to Our Regularly Scheduled Event Modeling...
Any good construction project begins with a solid foundation, and I've found a three-tier event model to be the best. It provides clear separation between user input, data interactions, and UI results. It's also undoubtedly the easiest way to start and maintain an event-driven application as it grows in complexity. It becomes a matter of choosing actions from a menu (your low-level events) that you can then plug into your middle-tier events and even if you have to add a tier in some cases, keeps things very consistent, clean, and even simple.

You want to know what a high-level event is? It's an event that shows up in the URL, either as part of a hyperlink or in a form field. It's expressed via URL syntax that, for example, says index.cfm?event=showMeTheMoney and tells the framework what action to perform. Back in the day when I used page-based development, I would have a page called listUsers.cfm. Now, I have an event called listUsers and the associated URL looks like this: index.cfm?event=listUsers. It's not untrue that you can, in general, just replace the word page with event and have a fairly clear picture of what we're up to here.

Take a look at Listing 1. We have three events listed to get one page. Undoubtedly the first thought that crosses your mind is: "Why on earth should I use three events to get one page on the screen?!?" Trust me, I understand! Although you don't need three events, this article is about tiered event models and the idea is to create your events in layers so you can later add to the basic model quickly and with a minimum of fuss.

Listing 2 is where the tiered event model really starts to click and the idea should really take hold. If you look at the top-tier event (home), you'll see that we've added a broadcast tag (which, in the case of ModelGlue, is how you tell the application to do things like interact with a database or the file system), and we've added result tags as well. Result tags are used to branch events. Like an implied condition (if-else), the result tags say, "If the controller sets a result named 'loggedIn', do this action, otherwise ignore me. If the controller sets a result named 'notLoggedIn', then do this other action." You can include the same result multiple times. For instance if you wanted to log views by logged-in users, you could have <result name="isLoggedIn" do="logAuthUserAction" /> and <result name="isLoggedIn" do="showView" />. This is how the ModelGlue controller sends information back to the framework's kernel.

From Simple to Complicated
By now it's fairly apparent that even simpler views should use this method for the sake of consistency and eventual maintenance. We can count on functionality expanding, and using a method like this allows you to easily plug new functionality into events. For a peek at how this can set the application up for the next level of complexity, see Listing 3.

Look at the middle-tier event ("homePage"). Notice that I've added a new section to the homePage event: broadcasts. This includes a message tag and an argument tag. This new section tells ModelGlue to look in the <controllers .../> section of the XML config file and find the message named getContent, then execute the associated method. In this case, we're using the <argument .../> tag to specify the name of the page for which to fetch content. It would be just as easy to specify the page being requested using a URL variable, or use these two in combination by using conditional logic to apply a default value in the absence of an explicit one.

For each of these events, the views are rendered into a variable named body, a fact that you can see by looking at the <view .../> tags. This makes it possible to have a single event named layout to process all the views. All three of the major frameworks support content variables to capture the content of screens for later output to the browser. In the file layout.cfm, you'll see <cfoutput> #viewState.getView("body")# </cfoutput> in ModelGlue. In the other frameworks you'll see similar syntax for doing the same thing. In Fusebox, you'll see a simple <cfoutput>#contentVariable#</cfoutput>. In Mach-II, you'll see the term contentKey instead of content variable, although the idea is still the same: collect the output of a particular event request and use a single layout.cfm template to draw the screen for return to the browser.

In general, however, your layout.cfm file provides a basic layout with header, footer, and navigation as shown in Listing 4. This file can be expanded upon, adding cfif tags to check for various content variables that may or may not be present. Some things will change based on the login status of the user, certain application conditions, and so on. It is recommended that each of these page fragments be generated into their own content variables and displayed by a layout template like the one shown in Listing 4. It's not uncommon to have more than one layout template for different site sections as the layouts change, allowing you to minimize the number of places in your application that need to be kept up during maintenance cycles.

Event-Driven Grid Layouts
Grid layouts are an effective technique for breaking complex pages down into manageable pieces. Portal sites often use a grid layout, breaking complex pages down into several columns and each column into small sections often called pods. This method makes complex pages easier to maintain while facilitating complex sites that are also easy to use. It also provides a good opportunity to demonstrate a slightly deeper event model because we can create a collection of events that will build our pods and tie them into any other middle-tier event. This creates a very modular design that couldn't be easier to maintain or expand upon.

Listing 5 illustrates a static collection of pods. The nice thing about this particular layout technique is that there is one event responsible for adding pods, and it spawns a self-contained process for creating one view fragment called pods that can be displayed by layout.cfm. It makes adding new pods incredibly easy. Simply add a new event for a new pod, then add the new pod to the getPods event. Nothing outside this process needs to know of the change because the getPods event simply creates a view fragment that is output in the layout.cfm file. Unfortunately, this doesn't allow for dynamically created pods, and if you have an application in which users are given the ability to choose the pods they wish to see once they've authenticated (e.g., see http://my.yahoo.com), there are just a few more changes that need to be made. Let's look at Listing 6.

It's not as complicated as it may seem at first:

I know you have to be thinking why on earth should I work in the XML file, in the model, in the view, and add the framework's overhead to the mix? It's going to bog down, run slow, and cause problems right? Wrong! If that were the case, then Macromedia.com, which runs on a mix of Mach-II with a little ModelGlue for flavor, would die at peak times every single day...but it doesn't. Why?

Because of well-planned architecture, design, and testing. Because using these techniques allows the creation of a pod system that can be plugged in anywhere in the application: written once, maintained in one place, but used wherever it may be needed or even just wanted. Once the initial design is working, there's testing and refactoring into faster and more efficient designs. Rendered content can be used with RAM-based caching or disk-based caching to accelerate response times. Hardware, server settings, and application code can be tweaked and tuned, but without very clearly structured and well-organized code you're going to start fighting an uphill battle from the beginning. It's cheaper in the long run to put more effort into design and architecture than to erect a mass of spaghetti code that will eventually turn into a maintenance nightmare.

So organize your code. Use events to create tight little routines that do as little as possible themselves and plug them into each other to create larger routines, then use high-level events to tie those together. For me it works well to start with the event model like we saw here, because it helps me see what my code will be doing. If you take anything away from this article, it should be that by using solid design principles we can create applications that are not just scalable, but stable under high load; easily maintained and upgraded; provide extremely high value to our clients; and just plain fun to build.

© 2008 SYS-CON Media Inc.