 |
 |
 |
 |
|
|
|
 |
|
In a Rich Internet Application, a Macromedia
Flash MX client provides the rich user experience,
while server-side programming (based on Macromedia
ColdFusion MX in this article) provides the
business logic and manipulates the data model.
Macromedia Flash Remoting enables communication
between the two.
Consider the performance of
such an application. Several key factors
impact performance, such as the size and complexity
of the Macromedia Flash MX client and the number
of connections and calls made from the client
to the server. |
|
|
| |
By definition,
a Macromedia Flash MX movie with a lot of complex ActionScript
is larger than a movie containing simpler logic. It takes
longer to download. A complex client also requires more
client-side CPU power.
It's a common challenge:
You want to produce a rich user experience but you don't
want to burden the client movie with a lot of complex
logic. On
the other hand, if you move all your logic to the server
side, the client will have to make a lot of network calls
to invoke
methods and retrieve data piece-by-piece. This reduces
performance because your application continually waits
for network responses.
This article examines how you can
manage this trade-off by applying well-known software
design patterns, such as
façade and value-object patterns, and illustrates
it by means of simple fictional e-commerce website application. Description of fictional e-commerce site "buying.com"
This fictional website's Macromedia Flash MX user interface
lets shoppers browse a product catalog, look at the details
for a product, put products in a shopping cart, and go through
a checkout process with credit card authorization.
The back end of buying.com runs on ColdFusion MX and consists
mainly of ColdFusion Components (CFCs) that handle each
of the main activities:
|
catalog.cfc |
|
product.cfc |
|
cart.cfc |
|
checkout.cfc |
Each component contains methods that support the possible
user interactions on the website. For example, the methods
in product.cfc return different attributes of the product.
The methods for cart.cfc allow a customer to put an item
into the cart, update its quantity, and retrieve the details
of an item in the cart. For checkout.cfc, there are multiple
methods: four separate methods gather the user's name, billing
address, shipping address and credit card respectively,
a method that authorizes payment, and another method that
completes the checkout.
In a naïve implementation (an unsophisticated implementation,
one that doesn't take into account best architecture practices),
the Macromedia Flash movie would probably make a NetService
connection to the gateway for each of these services, make
several remote calls to each service, and manipulate the
data returned by each call. The naïve implementation
ends up with a large, complex client that makes several
connections and many calls (see Figure 1).
|
| |
|

|
| |
|
Figure 1. A naïve implementation
of the e-commerce site
Reducing the number of calls
Several of the back-end CFCs offer set/get methods to provide
access to data. Generally, this is proper coding practice
because it avoids exposing the underlying data members of
the components. For example, product.cfc has methods to
get the product name, get the description, get the price,
get the icon, and so on. When you use this component locallyfor
instance, from other components or CFML pagesthe number
of calls it must make may not impact performance significantly.
When this component is used remotely through Macromedia
Flash Remoting, however, each call creates network traffic
and requires both a result callback (for a successful call)
and a status callback (for an unsuccessful call) in ActionScript.
This situation is similar to J2EE development when the
client layer makes calls to remote EJB instances. To solve
this problem, you pass back a single object containing all
of the data the client needs, instead of making multiple
calls to retrieve each piece of data. This is known as the
Value Object pattern. On the Sun Microsystems website, Sun
describes the Value
Object pattern in the J2EE
pattern catalog as follows:
Use a Value Object to encapsulate the business data. A single method
call is used to send and retrieve the Value Object. When the client requests
the enterprise bean for the business data, the enterprise bean can construct
the Value Object, populate it with its attribute values, and pass it by value
to the client.
Because Macromedia Flash Remoting can handle complex and
simple object types, you can "borrow" this pattern
for your Rich Internet Application. In this case, the Value
Object will most likely be a native ColdFusion typesuch
as an array, struct, or querythat can be passed through
Macromedia Flash Remoting and be manipulated as a native
ActionScript type in the client.
Many components, such as product.cfc in the example below,
perform a database query to retrieve underlying data and
expose that data through several get methods.
|
| |
<!--- product.cfc ---> <!--- without Value Object pattern - lots of 'get' methods ---> <cfcomponent> <cffunction name="getName" returntype="string"> <cfargument name="id" type="string"> ... </cffunction> <cffunction name="getPrice" returntype="numeric"> <cfargument name="id" type="string"> ... </cffunction> ... </cfcomponent>
These components can just as well return the entire query
result, which becomes a recordset in ActionScript. The client
can easily extract the data from the recordset instead of
making multiple calls.
<!--- product.cfc ---> <!--- with Value Object pattern - single 'get' method ---> <cfcomponent> <cffunction name="getProductInfo" returntype="query"> <cfargument name="id" type="string"> ... </cffunction> ... </cfcomponent>
The ActionScript changes from making calls, in the first
example, to getName(), getPrice(), and so forth to making
a single call, in the second example, to the getProductInfo()
method and then extracting the name, price, and so forth
from the recordset returned.
For the checkout.cfc component described above, clients
would have to make separate calls to set each of the billing
address, shipping address and credit card information.
<!--- checkout.cfc ---> <!--- without Value Object pattern - several 'set' methods ---> <cfcomponent> <cffunction name="setBillingAddress"> <cfargument name="address" type="struct"> ... </cffunction> <cffunction name="setShippingAddress"> <cfargument name="address" type="struct"> ... </cffunction> <cffunction name="setCreditCard"> <cfargument name="card" type="struct"> ... </cffunction> ... </cfcomponent>
Instead of passing a struct that contains an address to
each of the setXxxAddress methods and a struct containing
the credit card details, you would build a single struct
in ActionScript (with an entry for each billing address,
shipping address and credit card), and then pass that aggregate
struct to setCustomerDetails. In this way, you are making
one call instead of three, or one serialize/deserialize
operation instead of three, which means less traffic through
the Macromedia Flash Remoting gateway.
<!--- checkout.cfc ---> <!--- with Value Object pattern - single 'set' method ---> <cfcomponent> <cffunction name="setCustomerDetails"> <cfargument name="customer" type="struct"> ... </cffunction> ... </cfcomponent>
You might be concerned that this increases the complexity
of the client. In reality, it's just a trade-off between
two different types of complexity:
|
In the naïve implementation, the
client makes multiple calls and must coordinate all
of the result/status callbacks. |
|
In the Value Object implementation, the client makes
a single call, stores the result locally, and then accesses
the data from that local object (or constructs a single
local object with all of the client data, and makes
a single call to pass it to the server). |
|
| |
Reducing the
client's dependencies
Buying.com's back end contains only four components. The
client movie interface does not have to manage too many service
connections.
As you enhance this website, however, the number of components
that the client would need to interact with increases. Consider
if you were to add the following functionality to your application:
a membership function so users could return and view their
order history, an address book for users to save multiple
billing or shipping addresses, a promotions system to reward
loyal customers and tempt new ones, and cross-selling and
bundling for products. Each of these enhancements is likely
to add at least one ColdFusion component to the system and,
therefore, increase the number of service handles obtained
from the gateway.
Furthermore, the client movie ends up with
a lot of code
that is specific to the individual components and the
client code becomes harder to maintain because changes
to the back-end
components often require changes to the client layer.
Also consider that services exposed to Macromedia Flash
Remoting
are also necessarily exposed as general web services,
providing you the opportunity to offer your online store
as a service
to a large number of users with a variety of different
interfaces. The four components discussed so far would
not make an ideal
interface for a general web service!
Note that a very simplistic naïve implementation would
probably create a NetService connection object for each
component, possibly for each group of related method calls.
This can be mitigated purely within the Macromedia Flash
movie by using a single NetService connection object passed
around in global scope and, if necessary, saving each of
the service handles to the global scope as well. It should
be evident that the real challenge here, in terms of complexity,
is having to manage multiple services in the first place.
Creating a solution in a façade design pattern
Enter a software design pattern called a façade.
From the "Gang of Four" book, Design Patterns:
Elements of Reusable Object-Oriented Software, by Erich
Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley,
1995), façade is defined as follows:
Provide a unified interface to a set of interfaces in
a subsystem. Façade defines a higher-level interface
that makes the subsystem easier to use.
The façade that you create is a single ColdFusion
component that only exposes whatever functionality is necessary
to implement your online store. You will choose methods
in the façade that make sense to the client. (Note
that the four existing components most likely have methods
that make sense to the component in which they are defined.)
Some of these façade methods will aggregate the
functionality of several back-end methods and manage their
interactions. For example, whereas cart.cfc has a method
called updateQuantity that updates the quantity of a specific
item, the client would typically update all of the quantities
at once, so the façade would have a method called
updateCartQuantities that takes an array of quantities and
iterates over the array, calling cart.updateQuantity to
update the quantity for each item. Common patterns for user
interaction such as this can be moved from the client movie
to the façade, which simplifies the client and reduces
the coupling between the client and the specific back-end
components. Figure 2 shows a façade implementation
for an example e-commerce site.
|
| |
|

|
| |
|
Figure 2. A façade implementation
of the e-commerce site
Unlike the naïve implementation shown in Figure 1,
now there is only one NetService connection object needed.
The storefaçade.cfc component has absorbed some of the remaining
complexity of the client:
<!--- storefaçade.cfc ---> <cfcomponent> <!--- product services ---> <cffunction name="getProductByID" returntype="query"> <cfargument name="id" type="string"> <cfinvoke component="product" method="getProductInfo" id="#arguments.id#" returnvariable="result"> <cfreturn result> </cffunction> ... <!--- checkout services ---> <cffunction name="customerCheckout"> <cfargument name="customerDetails" type="struct"> <cfinvoke component="checkout" method="setCustomerDetails" customer="#arguments.customerDetails#"> <cfinvoke component="checkout" method="doCheckout" returnvariable="result"> <cfreturn result> </cffunction> ... </cfcomponent>
Notice how the façade allows you to provide better
names for the services and to combine actions, such as setting
the customer details and performing the checkout all in
one call.
Extending the e-commerce web application
One possible future enhancement for your e-commerce application
is to add membership functionality so that users can create
accounts, log in, store their billing and shipping addresses,
and review their order history. Membership may be provided
by components such as authenticate.cfc and userprofile.cfc,
but because this is something you'd want to use in several
of your websites, you should consider how to add this in
the most reusable manner. Instead of modifying the storefaçade.cfc
component to invoke these two new components, consider creating
a more generic membershipfaçade.cfc that provides the necessary
services using these two new components (log in, log out,
create account, update profile and so forth).
Changing storefaçade.cfc to extend membershipfaçade.cfc
adds in all the new membership functionality, so that the
Macromedia Flash MX client can access it in the online store.
The store façade provides an account history method
that combines the functionality from the membership façade
(user profile) with that of the checkout process, and records
each user's orders in his or her profile.
Alternatively, you might create a Macromedia Flash MX client
for the membership façade to provide a "membership
hub" where users can manage all generic aspects of
their accounts. The online store's Macromedia Flash movie
can then load the membership movie and tell it to connect
to the single storefaçade.cfc service that the online store
already manages. Figure 3 shows a membership/store façade
implementation.
|
|

|
|
Figure 3. Membership/Store façade
implementation
By applying two fairly straightforward design patterns,
Façade and Value Object, that are typically used
in the C++ and Java worlds to your Macromedia Flash MX and
ColdFusion MX application, you have simplified your Macromedia
Flash MX client and reduced the amount of network traffic
the application generates. Both of these factors improve
the performance of the application.
Selecting suitable high-level façades for segments
of your application makes it easier for you to extend and
enhance your application, while retaining the performance
benefits of these patterns.
|
|
|
About the author
Sean Corfield, Macromedia's director of architecture,
brings 20 years of technical and managerial experience in
architecture, web technologies, and programming languages.
He has expert knowledge in UML, OOA/D, CASE, C, C++, Java,
SQL, Broadvision, ColdFusion, and HTML. He relishes a technical
challenge both inside and outside of work and healthy technical
debates. You can contact him at scorfield@macromedia.com.
|
| |
|
|
|