OCCASIONAL CF NEWSLETTER
September 1999
This is a special issue. I'll be putting another one out in early September, but I wanted to talk at some length about using an object-based methodology with CF. As some of you may know, I've been working on extending the Fusebox specifications (www.fusebox.org) into a full-blown methodology that takes the best practices of Fusebox and goes beyond that to help developers through the entire development process--from getting user requirements through deployment and testing.
Since Fusebox is based around the concept of objects, I thought it might be helpful to explore what objects are, how they work, and why you may want to adopt them in your work. Along the way, we'll look at using WDDX to really help out with this process.
Let's say you're heading up work on a large intranet project. Here's a checklist of some of the requirements:
- user must log into and be validated by system as user, supervisor or administrator
- user can belong to one or more groups
- depending on which group(s) user belongs to, a menu of choices is presented
- there will be a library of documents that users can download. Some are restricted to certain user groups.
- there should be a directory of employees
- system can handle action items, presenting an inbox and outbox of action items for each employee
- users can sign up for company training
Your development team is scattered across the country, to make matters more complicated. OK, let's get coding! Not yet, you say? Well, I agree. Before we do any coding, we need to "chunk" the program into manageable pieces. How do you want to do it?
If you're starting to think in terms of separating pieces by function -- maybe a separate "action item manager", a "user manager", a "document manager", maybe a "training manager" -- then you've just invented objects. An object is just a way of chunking tasks in order to reduce the difficulty of working with any one piece.
In traditional object-oriented languages, there are several mechanisms built into the language that make this task easier. ColdFusion isn't an "OO" language, but I'm going to illustrate how you can use an object-based approach to make development easier--especially with a team scattered in different locations.
Now that you have the concept of an object--let's say the "action item manager"--it's easy to see what user actions properly belong to it: things like "create an action item", "view all my action items" and "complete an action item". So you give the job of creating this "object" to your coder in San Diego.
Of course, stuff like "add a user", "log in a user" and "validate a user" belong to the "user manager" so you give the job of building this object to your coder who's in Atlanta. Off they go, coding like mad.
Your San Diego-"action item manager" coder needs a list of all people their user can send an action item to. So the San Diego coder...does what? If you're thinking "query the database", let me ask you a question. What happens if at some point the decision is made to move from storing users in a database to, say, storing users in an LDAP server?
Do you see the problem? All the code that relies on querying the database will break. Or at the very least, it will force everyone who needs user information to learn all about LDAP servers. That's expensive in terms of time and maybe money, depending on what has to be learned.
The object-based way around this is to "encapsulate" functionality very tightly within the object. If the action item manager needs information about the user, s/he gets it only by ASKing the user manager for that list. It's entirely in the User Manager's domain what she does to get that information. By having a well-defined interface -- a set of requests an object will respond to -- we can have the San Diego coder go about her work without worrying or waiting for the DB/LDAP server issue to get resolved.
In ColdFusion we can create objects by writing code that looks for specific requests and then responds to them. To make life easier on everybody, let's call the code file exactly what we mean it to be -- so one will be ActionItemMgr.cfm and another UserMgr.cfm. And let's look at the innards of the UserManager.cfm file...
<!-- UserManager.cfm -->
<cfoutput>
<cfswitch expression="#attributes.request#">
<!--- If request is "allUsers", I return a list of
all users in the system. --->
<cfcase value="allUsers">
<cfquery datasource="ds" name="getUsers">
SELECT
userID,
firstName,
lastName
FROM
Users
ORDER BY
lastName
</cfquery>
<!--- Now I'll wrap this up and send it back
to whoever called me. --->
<cfwddx
action="cfml2wddx"
input="#getUsers#"
output="caller.UserManager.allUsers">
</cfcase>
</cfswitch>
</cfoutput>
The whole of the code is a single CFCASE statement set inside a CFSWITCH tag -- waiting for the a "request" variable to be passed into it. I've stripped down this fuse for brevity; normally, the object code consists of several case statements that, all together, define the interface for the object. Our UserManager.cfm code patiently waits for a request for allUsers. When it gets such a request, it provides the userID, firstName and lastName for all users. And does this it in an interesting way.
Web Distributed Data Exchange or "WDDX" is a new technology and it solves the problem of getting complex data from one page to another. I won't get into the particulars other than to say that it uses XML to store both data and information ABOUT the data (so-called "metadata") in a simple, common string format. And of course, you know how to pass strings around. If they're small, you can put them in your URL query string. More often, you'll put them into a form variable.
Why is this important? Well, we said we wanted the action item manager to request information about users from the user manager. But how do we get the results of a query back from the user manager? ColdFusion 4.0 introduces a CFWDDX tag that makes using this new technology very easy. (Thank you, Allaire.)
The code takes the results of the "getUsers" query and uses this as the INPUT parameter of the CFWDDX tag. The ACTION is CFML2WDDX--meaning that we want to take ColdFusion variables and turn them into that WDDX string. By using a "caller." prefix to the OUTPUT parameter, we're tipping our hand that we intend this tag to be called as a custom tag. (That's also the reason for the "attributes." prefix on the variables.)
Back to our coder in San Diego, when she wants to get a list of all the users in the system, she can use this call:
<cfmodule
template="UserManager.cfm"
request="allUsers">
and use this corresponding CFWDDX tag to turn it back into a normal ColdFusion query result set, just as if she had run the query in her page.
<cfwddx
action="wddx2cfml"
input="#UserManager.userInfo#"
output="allUsers">
<cfoutput query="allUsers">
#lastName#, #firstName#
</cfoutput>
Computers are incorporated in modern ice cream vending machines to enhance their functionality. Ice Cream Vending machines are manufactured by many companies. Your competition will try to overcome all requests for high-tech ice cream vending machines and credit card acceptors
|
|
It turns out that communicating through interfaces is really handy for distributed teams. If a coder in one place needs to get information from a coder in another place, he or she can use email to ask, "Hey User Manager, I need to check on what groups a user belongs to. How do I do it?" To which, the User Manager will make a note to include a "userGroups" request as part of their interface and sends an email back to the first coder saying "Use 'userGroups' and you'll get back a comma-delimited list of the groupID of all the groups the user belongs to." This lets substantial coding go on even before the object interfaces are frozen.
So objects work out to be pretty helpful--even in a non-OO language like ColdFusion.
|