Doug's Resume
OO Lexicon
Chat with Doug!
Recent Entries
You may also be interested in...

heaters
hotels boeken in 7 sec
Engagement Rings
Online Dating Australia




SURF'S UP!
You:
Your Web Site:
<< March, 2007 >>
SMTWTFS
123
45678910
11121314151617
18192021222324
25262728293031
Search Blog

ColdFusion Jobs
Recent Comments
Re: Viewing Option Text (in IE7) that's Wider than the Select List (by Dan Roberts at 5/15 2:38 PM)
Re: Viewing Option Text (in IE7) that's Wider than the Select List (by Dan Roberts at 5/15 10:06 AM)
Re: Inline CSS and Ajax Issue with IE (by Ben Nadel at 5/14 11:50 AM)
Re: The Perfect Alternative to Gas Powered Vehicles (by Thomas Messier at 5/09 12:47 PM)
Re: Promoting Family Unity: Lowering Your Utility Bills! (by Fernando Lopez at 5/07 10:12 PM)
Re: Why I Hate ORMs (a solicited rant) (by Richard at 5/06 10:56 AM)
Re: Why I Hate ORMs (a solicited rant) (by dougboude at 5/06 10:27 AM)
Re: Why I Hate ORMs (a solicited rant) (by Richard at 5/06 6:50 AM)
Re: Why I Hate ORMs (a solicited rant) (by Sean Corfield at 5/06 1:40 AM)
Re: Why I Hate ORMs (a solicited rant) (by Steve Bryant at 5/05 5:07 PM)
Categories
Archives
Photo Albums
Funnies (5)
Family (3)
RSS
Reciprocal Links

Powered by
BlogCFM v1.11

27 March 2007
Just What IS Abstraction, Anyway?
Consider scenario 1:

It's Saturday, and I have a list of chores to do.
  1.  Throw the laundry into the washer;
  2.  Do the dishes;
  3.  Scoop the cat poop out of the litter box;

So, I take the laundry out of the basket in my closet and put it into the washer. I dump in one cup of SudSoClean, set the temp to warm, set the load size to medium, and start the cycle.

Next, I move all the dishes out of the sink and onto the counter, wash out the sink, put the drain-stopper in, and fill it with hot soapy water. I put the silverware in first so it can soak the longest, then the plates, and lastly cups. As I wash a dish, I rinse it in the other side of the sink under warm water, then set it on the towel to drain while i finish washing the rest of the dishes.

Saving the worst for last, I get a plastic bag from the kitchen drawer and take it to the cat litter box. I get the plastic strainer scooper thingy out of its container, remove the lid to the litter box, and start scooping out little cat tootsie rolls and putting them into the bag. When I'm finished, I add some fresh cat litter, put the lid back on the litter box, and slide it back into place.

Whew! That was hard work, wasn't it boys and girls!

You know what. I think I'll abstract my chores by adding something between them and myself: my kids!

Consider scenario 2, with me doing my chores after having abstracted them:

I call out to objBrandon and ask him to do the laundry (<cfset laundrydone = objBrandon.doLaundry()>);

I call out to objLilly to do the dishes (<cfset dishesDone = objLilly.doDishes()>);

I call out to objSarah to scoop the kitty litter (<cfset noMoTootsies = objSarah.scoopLitter()>);

Hey! I'm done with my chores!

Abstraction: removing the actual work from myself and executing it by commanding someone else to do it.

It's easy to see why I'd want to abstract my chores. But in an application, WHY would I want to add yet another layer to what may already be somewhat complex?

Because...the way the actual work gets done just might change, and if I have the work abstracted out to individual objects, making those changes is all done in one place.

As an illustration, consider a change to the process for washing my dishes. Now, instead of doing them in the sink, I give in and allow the new process to be rinsing them and stacking them in the dishwasher. I re-write the routine for objLilly, but my call to her to doDishes(), and in fact, anybody else's call to her for the same does not change. Because we've abstracted that chore, the "business logic" associated with it is entirely encapsulated (contained) and found in one place.

In the context of an application, if we DID follow the advice of a peer and "create an abstraction layer for managing persistent variables (such as session variables)", then when the day came that we found a need to stop storing values in session and switch instead to client variables, we don't have to hunt and peck all over our code for every occurrence where a session var gets set; we need only go to our Persistence object and make the needed changes right there.

Abstraction - it's what's for dinner.

Abstraction - the other white meat.

Abstraction - not such a vague term after all, is it?
Posted by dougboude at 2:11 PM | PRINT THIS POST! | Link | 12 comments



22 March 2007
Just What IS the Factory Pattern, Anyway?
A Factory makes things, right? And that is precisely what is being referred to when someone talks about a Factory, or the Factory Pattern: an object or framework whose job it is to create other objects for you.
So, rather than create your own object yourself like so:

<cfset myObject = createobject("component",model.myObject)>

 
You would call upon your Factory object to make it for you, similar to the following:

<cfset myObject = myFactoryObject.MakeMeAnObject(obj = “model.myObject”,args = stArgs) >

 
If you opt to have an object create your other objects for you, thenYOU, O Best Beloved, are a user of the Factory Pattern, and may boast of it in public settings as the mood strikes you.

Here’s a question that’s BEGGING to be asked: WHY would anybody wanna add that level of complexity to their app???

I’ll have to respond to that question with another question: Has it crossed your mind that sometimes, perhaps, one object might need an instance of another object inside of itself in order to do some kind of work?

Whether it has or hasn’t crossed your mind, the fact is that many times this will be the case, especially when you’re writing your app around an MVC framework. Now, the traditional method of making one object available within another object would be to simply write a line of code within your CFC that instantiates the other object, such as in our example above. However, what if you are using this same CFC…we’ll say, a CFC that performs emailing duties, within many other objects? Then one day you make a change to the Email.sendMail() method that requires an additional parameter be passed in. You would have to go to every other CFC that instantiates the Email.CFC and modify that line of code to accommodate the new parameter. Could take a long time, you might miss one, etc. Using a Factory, however (such as the Coldspring framework, which I am totally in love with), you can make that change in one place and the Factory will ensure the change is cascaded appropriately.

So what would be a real world scenario where I would actually need one object inside of another? Hmmm…how about registering a new user for access to a site? The steps involved with registering a new user are:

  1. create the user record
  2. send the user an email.

In order to keep my functionality all segregated nice and neat so i can use it here and there, I have myself a User object that handles user records, and an Email object that performs emailing duties. Since my registration process means I need to be able to perform functionality from both the User object AND the email object, I create a third object called RegistrationService.CFC that will do nothing more than orchestrate, or coordinate, work that the User and Email objects know how to do. This scenario is just one of many compelling reasons to utilize a factory.

(FYI, that coordination of work is what makes RegistrationService a service layer object...not the fact that it has 'Service' in the name.)

One last thought...Factory Pattern…this is another one of those “patterns” that I do not consider to be a pattern of any sort. From my real world experience, an object can BE a Factory, or you could even create an entire application (or framework) whose job it is to BE a Factory…but a pattern of factories? Nah, doesn’t gel.

Doug out.

Posted by dougboude at 5:16 PM | PRINT THIS POST! | Link | 1 comment
Just What IS the Singleton Pattern, Anyway?

You, O Best Beloved, are a Singleton. There is nobody else like you in the whole wide world, nor has there ever been. You’re a singular occurrence, a unique random combination of genetics that exists only wherever you happen to be at a given moment. And if any of  your friends wants to interact with you, they know just where to find you. You can interact with lots of different people, but no matter how many friends you may have, every one of them is interacting with the exact same YOU. When your good friend Dave asks you to tell Theresa hello next time you see her, you store that information and next time you interact with Theresa, you pass along that exact message.

 
You getting the picture here? If you instantiate a CFC and put it in a place (Application scope, anyone?) where EVERY other part of your application is able to interact with THAT PARTICULAR instance of your CFC, then YOU, O Best Beloved, have created your object as a Singleton. Now, for whatever reason, people seem to be awfully fond of tossing around the buzz phrase “Singleton Pattern”…not sure why. It’s way simpler just to use the word as an adjective describing how you have instantiated your object, and it makes more sense, too.

 A few other thoughts on Singletons…
 

  • It’s vital to understand this term because it has a huge effect on how your app will work. Basically, if an object is created as a Singleton and you aren’t able to visualize what that means, you could have people seeing other people’s data. Not good.
  • That I’m aware of, there is no opposite of Singleton...an object either IS a Singleton, or it isn't.

 
POP QUIZ!

Which of the lines of code below is creating my object as a Singleton?

A) <cfset adminObject = createobject("component",model.admin) >

B) <cfset application.adminObject = createobject("component",model.admin) >

Posted by dougboude at 4:41 PM | PRINT THIS POST! | Link | 13 comments
19 March 2007
Using Ajax with Model-Glue - it's really quite simple
At first glance, the topic can seem somewhat overwhelming. The key, however, is to understand each of them separately and then using them together won't seem overwhelming in the least. I'll touch briefly on each of them independently, but will assume for the bulk of this post that you have at least an elementary understanding of what each is and generally how they work.

Ajax refers to the ability we have to make Javascript run back to our web server and retrieve information for us, without reloading the entire page. It is doing nothing more than making an http call to a web page, just like we would do everytime we click a link on a page. The Javascript, however, makes the call in the background, unseen by the user, receives whatever content results from that web page call, and then does something with it inside of our current page.


Model-Glue is a popular Coldfusion application framework that is becoming the "procedural man's tour guide to object oriented programming", breaking "the rest of us" into the world of OO. If you haven't played with it or invested the time to get familiar with it, you have a lot of your peers who HIGHLY recommend it. I recently had the privilege of doing a presentation for the Kansas City ColdFusion User's Group on Model-Glue that was saved as a Breeze preso if you need or want some kind of intro.

Okay, from this point forward I can safely assume that you have at least a working understanding of Ajax and Model-Glue as separate tools, and will now share with you how the two integrate easily (from the 1,000 foot view). I will NOT be focusing on any one Ajax library, as there are several good ones out there, and as the specific Ajax library being used is (or should be, if the Ajax library is intuitive enough) COMPLETELY IRRELEVANT to understanding how they integrate with one another.

First thing, consider a basic Model-Glue event lifecycle:

1. A Model-Glue event is called via navigation to a URL (index.cfm?event=app.home).
2. The Model-Glue framework looks up the event (in the modelglue.xml file), determines what broadcasts to make, what results to evaluate, and what views to render.
3. Rendered views are returned to the browser.
4. Browser displayes the rendered view.

Hmm, nothing complex here, eh?

Now consider a basic Ajax call to a Model-Glue event:
1. A Model-Glue event is called via Javascript library (var newcontent = ajax.remotecall('index.cfm?event=ajax.getInfo');).
2. The Model-Glue framework looks up the event (in the modelglue.xml file), determines what broadcasts to make, what results to evaluate, and what views to render.
3. Rendered views are returned to the browser.
4. Javascript receives the rendered view and does whatever it was told to do with it (document.getElementById('ajaxDiv').innerHTML = newcontent;)!!

So what is different when incorporating Ajax into the mix? Very, very little. The only REAL difference that I've found I need to keep in mind is in regard to what my view contains when the event I'm calling was specifically created for an Ajax call. For instance, in a "normal" event call, i'm typically going to be returning an entire html page, complete with body tags and the works. In an Ajax call, it will be either a chunk of html or some kind of Javascript-ready data (XML, JSON data, etc.) I have found that it's simpler, whenever possible, to return a chunk of pre-rendered HTML and have my client-side javascript simply place the returned html into the target div. Working with returned XML is where Ajax will become more complex, but even then, the complexity is STILL on the client side JS coding and not anything to do with Model-Glue at all.

I don't believe that there's anything else a person needs to know in order to be able to "think about" and visualize the interaction between Model-Glue and Ajax...it really is straightforward stuff! Not sure why just a few months ago it sounded like such a difficult concept to me....

Here's an illustration showing how Ajax would work with a Model-Glue page:



The actual Javascript that would handle the call could be as simple as the following example:
<!--- First, we load up the ajax library... --->
<script src="/js/AjaxLibrary.js" type="text/javascript"></script>

<!--- Now define the function we'll be using when the user clicks our "Ajaxified" link... --->
<script>         
function gotClicked(){
    /*first, retrieve the new content ... */
    var newcontent = ajax.remotecall('index.cfm?event=ajax.getInfo');
    /*now stuff the newly retrieved content into our ajaxDiv... */
    document.getElementById('ajaxDiv').innerHTML = newcontent;
}
</script>

That's it, really! Nothing more to it. After grasping this very basic understanding, the only thing left to do now is to select an Ajax library (personally, I take a shine to Scriptaculous...) and start learning how to use it!

Doug out.
Posted by dougboude at 11:34 PM | PRINT THIS POST! | Link | 3 comments
05 March 2007
Coldspring Automagic Lesson
Okay, I spent the greater part of today at work wrestling with a situation involving the injection of objects into other objects using Coldspring. After far too many hours of experimentation, furrowed brow, taking up my teammate's time, and frustration, I came to some conclusions. I can't explain the "WHY's" of the conclusions, but i can definately validate the conclusions themselves by my results.

Here's the scenario:

I have object B which extends object A. Object A has an INIT method, object B does not. Object B is being injected into object C. In my Coldspring.xml, I define a bean for object A, B, and C. Object A has a property value ("thisURL") being set via a <property> and <value> tag; object C has object B injected via a <property> and <ref> tag.  (see illustration and coldspring.xml snippet)

The Challenge (there are no problems, only challenges): When all objects are instantiated, I am calling method Y on object C. Method Y itself refers to a method X in the injected object B. Method X in injected object B refers to the property "thisURL" that was set via Coldspring within object A. WE GET AN ERROR, HOWEVER, INDICATING THAT THE VALUE IN OBJECT A WAS NEVER SET!

The Experimentation:
Hmmm, let's put a CFABORT tag in the "setThisURL" method in object A (the method needed by Coldspring in order to 'auto-inject'), with a 'ShowError' attribute. The abort is never executed, meaning that Coldspring never called the 'setThisURL' method on object A, despite the fact that we configured it to do so.

Okay, let's move everything we need into object B, remove the "Extends" attribute from the cfcomponent tag, re-do our Coldspring.XML to inject the 'thisURL' property directly into object B. Hey, it works!

Let's move it all back again, and try adding an init method to object B that performs a "Super.init()" to see if that fixes it. NOPE.

In my mind, in the mind of my peers, configuring Object A to have a property value injected should have resulted in Coldspring executing the "setThisURL" method. In fact, I NEED it to do that, because I plan on utilzing this base class (object A) by extending it with other objects as well, and the constant 'thisURL' needs to be present and the same in all cases. However, it did not behave in the expected manner.

As I stated at the beginning, I have NO idea why it did not behave as I expected. But, I thought I'd share the results of my headache in case it helps someone else avoid one later.

Conclusion:
The only way to make this work was to have Coldspring set the 'thisURL' property directly in object B if I wanted to be able to access it after having extended object A.

Illustration and Coldspring.xml snippet:


Snippet:
<bean id="objectA" class="model.objectA" >
    <property name="thisURL">
          <value>http://my.testserver.com/myWS.cfc?wsdl</value>
    </property>
</bean>

<bean id="
objectB" class="model.objectB" />

<bean id="
objectC" class="model.objectC" >
     <property name="objectB">
         <ref bean="objectB" />
    </property>   
</bean>

(back to top)
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 11 comments
02 March 2007
Dynamic Data Stores: A Model-Glue/OO Case Study
The scenario is that my team and I are building an app that must be able to seamlessly communicate between multiple datastores; one local, and the remainder remote and accessible via web service calls. In order to accommodate this, I've created a DataStoreAdapter component that has an instance of each of the specific data store interface components injected into it by Coldspring.

The challenge here was to find a way to dynamically call the appropriate methods on the appropriate data store object. After several different attempts, following is what I came up with that works (you may want to first sneak a peek at the visual I added to this post):


1. My user object (nestled within my user service layer) calls a generic method (named appropriately "callMethod") on the DataStore Adapter:

<cfset stResults = getUserDataStoreAdapter().callMethod(argumentCollection=arguments) />

(note: one of the arguments being passed in within the argumentcollection is 'methodname' with a value of 'getUserData')

2. The 'callMethod' method in the datastore adapter dynamically invokes the appropriate generic method:
    <cffunction ACCESS="public" name="callMethod" OUTPUT="false" RETURNTYPE="any" DESCRIPTION="I am the generic method that calls the appropriate backend system.">
        <cfargument name="backendSystem" TYPE="string" REQUIRED="yes" HINT="I am the name of the targeted backend system" />
        <cfargument name="methodName" TYPE="string" REQUIRED="yes" HINT="I am the name of the method to call within the targeted backend system" />
        <cfset var local = structnew() />
       
        <cfinvoke argumentcollection = "#arguments#" method = "#arguments.methodName#" returnvariable = "local.myResults" />
       
        <cfreturn local.myResults />
    </cffunction>

(arguments.method name in this case = "getUserData")

3. The generic method that was called invokes the appropriate specific method to return the autowired object needed, then the appropriate method is called from the specific backend object returned by the invoke:
    <cffunction access="private" name="getUserData" OUTPUT="false" returntype="any" DESCRIPTION="I am the generic getUserData function" >
        <!--- incoming argument collection is implied, no need to specify individual arguments. --->
        <cfset var local = structnew() />
       
        <!--- step 1: Make the call to the appropriate backend system... --->
        <cfinvoke  method = "get#arguments.backendSystem#User" returnvariable = "local.myObject" />

        <!--- we're invoking the backend-specific method from the appropriate object in the following line... --->
        <cfreturn local.myObject.getUserData(argumentcollection=arguments) />
    </cffunction>

(notice this specific method is private...can only be invoked by the "callMethod" method...)

4. The returned data is passed back up the calling chain to the original calling component.

Here's a diagram that might help to visualize it better.

Back to Top
All data massaging is encapsulated in the lowest level backend system components, so that each of them will return a consistent data set regardless of what they themselves are receiving from the backend system. And, as our upper management dictates that we interface with yet ANOTHER wack backend system, all we'll need to do is create the low level component and wire it in to our datastore adapter service!

Anyway, I was pretty pleased with how we addressed this situation so thought I'd share it.

Doug out.
Posted by dougboude at 4:35 PM | PRINT THIS POST! | Link | 1 comment
Sweet Little Snippet: Query to Arguments
I have a CFC method with one argument that is an incoming, single-row query:

<cfargument NAME="remoteData" TYPE="query" REQUIRED="yes" DISPLAYNAME="remoteData" HINT="I am the query returned (and formatted) from a remote data store." />

This method will call another internal method X in order to perform some work, but method X will be looking for the query data as arguments (necessary because method X is also used by other methods who will pass in discrete argument values).

So, I need to "convert" my 'remoteData' argument to actual argument values before I call the other method.


<!--- add our remoteData values to the arguments... --->
<cfloop list = "#arguments.remoteData.columnlist#" index="f">
     <cfset arguments[f] = remoteData[f][1] />
</cfloop>
<cfset myResults = methodX(argumentcollection = arguments) />
<cfreturn myResults />


Pretty simple, but not necessarily so straightforward when having to treat queries as a structure of arrays, so thought I'd share it.

As an aside, I went ahead and toyed with converting an entire query to a structure dynamically, too. Following is the snippet I used:


<!--- create a query to play with using querysim... --->
<cf_querysim>
UserInfo
userID,firstName,lastName,userGroups
100|Stan|Cox|33
200|Joe|Blow|35
</cf_querysim>

<cfset stArgs = structnew() />

<!--- put the query to a structure... --->
<cfoutput query="UserInfo">
    <cfset thisKey = "Record" & UserInfo.currentrow />
    <cfloop list = "#UserInfo.columnlist#" index="f">
        <cfset stArgs[thisKey][f] = UserInfo[f][UserInfo.currentrow] />
    </cfloop>
</cfoutput>

<cfdump var="#UserInfo#">
<cfdump var="#stArgs#" />

Pretty cool. Here are the dumps:




Doug out.
Posted by dougboude at 11:13 AM | PRINT THIS POST! | Link | 2 comments