Categories
Contact Doug!
Learn About Doug!
View Doug Boude's online resume
updated 11/18/2009

View Doug Boude's profile on LinkedIn
Link to me!

Follow Doug Boude on Twitter
Follow me!

Be Doug's friend on Facebook
Befriend me!
(I promise not to follow you home)
OO Lexicon
Chat with Doug!
Recent Entries
You may also be interested in...
Web Hosting

<< June, 2007 >>
SMTWTFS
12
3456789
10111213141516
17181920212223
24252627282930
Search Blog

Recent Comments
Re: Equivalent of SQL "TOP X" in Oracle (by Mark Foster at 7/07 4:04 PM)
Re: SQL Forward Engineering with Visio 2003 Professional (by Thomas at 6/26 4:41 AM)
Re: One Shot Query to Recalculate Orderby Field - MySQL (by gary at 6/17 6:46 PM)
Re: DON'T GET SICK IN ARKANSAS! (by r. wood at 5/25 12:00 AM)
Re: SQL Forward Engineering with Visio 2003 Professional (by Andrew at 4/30 6:14 AM)
Re: Basic Ajax Select List Filter in PHP (by good at 2/04 5:26 AM)
Re: Family Law: The Weapon of Choice for Woman Scorned (by swalker at 2/03 2:15 AM)
Re: Approaches to Building Strings: The Imploding Array (by bantal silikon at 2/01 9:44 PM)
Re: Disappearing IE Popup Window During Save/Open Dialog (by AddisonDean at 1/15 9:59 AM)
Re: My Top 20 Life Lessons for Boys and Young Men (by Alex at 1/13 8:45 PM)
Re: Array Loop Modifications in CFSCRIPT (by Alex at 11/25 11:18 AM)
Re: Array Loop Modifications in CFSCRIPT (by Abram at 11/14 11:32 PM)
Re: Recursive Functions in ColdFusion (by Dwayne at 10/25 3:47 PM)
Re: Porting Coldfusion Code to Mura (by dh at 10/16 10:14 AM)
Re: Viewing Option Text (in IE7) that's Wider than the Select List (by Devil May Cry at 9/26 1:38 AM)
Re: Why I Hate ORMs (a solicited rant) (by guideX at 9/12 11:38 PM)
Re: Recursive Functions in ColdFusion (by KP at 8/08 7:13 PM)
Re: American Airlines, YOU SUCK! (by Alison at 7/23 4:48 PM)
Re: SQL Forward Engineering with Visio 2003 Professional (by Harshad at 7/11 9:17 AM)
Re: Disappearing IE Popup Window During Save/Open Dialog (by LZ at 4/20 7:58 AM)
Archives
Photo Albums
Funnies (5)
Family (3)
RSS

Powered by
BlogCFM v1.11

20 June 2007
Circular Dependency Experiment
Circular Dependency is a phrase used to describe two objects who both use one another internally. That's simple enough. But...how the heck do those two OBJs get inside each other? And how do they behave once they're in there? These were some of the questions I needed answers to, and so I'd like to share with you my experiment and some of the things it taught me about circular object dependency.

I basically had the following questions I wanted to answer:

  1. How can I successfully get instantiated objects inside one another?
  2. Once instantiated, does object 2's manipulation of its internal copy of object 1 affect object 1's state, and vica versa?

Getting Objects Inside One Another
Okay, so how do we get an object inside another object? We inject it (embrace the phrase, you're gonna hear it a lot in the OO world!). With Coldfusion CFCs, this can be done one of two ways that I'm aware of: using "Setter Injection", or "Constructor Argument Injection". The Coldspring framework does that very thing for us when we leverage it in our apps, BUT I wanted to know what the raw, manual process of doing so looked like, so I created two sets of rudimentary CFCs, each of which has circular dependencies within them.

The first set (CFC1 and CFC2) have dependencies which utilize setter injection; The second set (CFCA and CFCB) use constructor arguments to get inside each other. CFC1 and CFC2 are identical, code-wise, as are CFCA and CFCB. Here is what they look like:
CFC1 and 2:
<cfcomponent displayname="CFC1 and CFC2">
    <cffunction name="init" access="public" returntype="any">
        <cfreturn this>
    </cffunction>
    <cffunction name="getMyName" access="public" returntype="string">
        <cfreturn variables._myname />
    </cffunction>
    <cffunction name="setMyName" access="public" returntype="void">
        <cfargument name="newname" type="string" required="true" />
        <cfset variables._myname = arguments.newname />
    </cffunction>   
    <cffunction name="getObj2" access="public" returntype="any">
        <cfreturn variables._obj2 />
    </cffunction>
    <cffunction name="setObj2" access="public" returntype="void">
        <cfargument name="obj2" type="any" required="true" />
        <cfset variables._obj2 = arguments.obj2 />
    </cffunction>
</cfcomponent>

(The Setter Injection method, as seen in CFC1, simply utilizes a "setObj2" method to set an internal variables-scoped variable to hold an instantiated copy of CFC2)


CFCA and B:
<cfcomponent displayname="CFCA and CFCB">
    <cffunction name="init" access="public" returntype="any">
        <cfargument name="obj2" type="any" required="true" />
        <cfargument name="myName" type="string" required="true" />
        <cfset variables._myName = arguments.myName />
        <cfset variables._obj2 = arguments.obj2 />
        <cfreturn this>
    </cffunction>
    <cffunction name="getMyName" access="public" returntype="string">
        <cfreturn variables._myname />
    </cffunction>
    <cffunction name="setMyName" access="public" returntype="void">
        <cfargument name="newname" type="string" required="true" />
        <cfset variables._myname = arguments.newname />
    </cffunction>   
    <cffunction name="getObj2" access="public" returntype="any">
        <cfreturn variables._obj2 />
    </cffunction>
    <cffunction name="setObj2" access="public" returntype="void">
        <cfargument name="obj2" type="any" required="true" />
        <cfset variables._obj2 = arguments.obj2 />
    </cffunction>
</cfcomponent>

(Notice that I still do have setters and getters for obj2; I didn't really have to have a setter, but the getter is needed so I can retrieve obj2 and call its methods)

Here is the code I used to instantiate CFC1 and CFC2 using the Setter Injection method:
<cfscript>
    //circular dependency using setter injection...
    obj1 = createobject("component","CFC1").init();
    obj2 = createobject("component","CFC2").init();
    obj1.setMyName(newname="Object 1");
    obj1.setObj2(obj2);
    obj2.setMyName(newname="Object 2");
    obj2.setObj2(obj1);
</cfscript>

Here is the code I used to instantiate CFCA and CFCB using the constructor argument method:
<cfscript>
    //circular dependency using constructor argument injection
    objA = createobject("component","CFCA");
    objB = createobject("component","CFCB");
    objA.init(obj2 = objB.init(obj2 = objA,myName="object B"),myName="object A");
</cfscript>

Okay, everything instantiated without any errors! Cool, and I have answered my first question. Now for question 2...

Object Behavior
How do these objects behave when set up in this fashion? To find out, I conducted interviews with each of the objects. Following are some exerpts and code snippets from those interviews (full interview can be seen here):

Interviewing obj1...

Q: What is your name?
A: My name is Object 1!
My name is #obj1.getMyName()#!
Q: What is your dependent object's name?
A: My dependent object's name is Object 2!
My dependent object's name is #obj1.getObj2().getMyName()#!

Interviewing obj2...

Q: What is your name?
A: My name is Object 2!
My name is #obj2.getMyName()#!

Q: What is your dependent object's name?
A: My dependent object's name is Object 1!
My dependent object's name is #obj2.getObj2().getMyName()#!

Q: Can you change your dependent object's name?
A: I don't know...let's give it a try, shall we?
(lots of grunting and straining sounds can be heard...)
<cfscript>
    obj2.getObj2().setMyName(newname="Eduardo");
</cfscript>

I think I did it! My dependent object's name is NOW Eduardo!
I think I did it! My dependent object's name is NOW #obj2.getObj2().getMyName()#!

Interviewing obj1 again...

Q: What is your name NOW, obj1?
A: My name is Eduardo!
My name is #obj1.getMyName()#!

Q: Why don't you go ahead and try to change YOUR dependent object's name...
A: Sure thing! My dependent object's new name is Florence. He he he he he.
<cfscript>
    obj1.getObj2().setMyName(newname="Florence");
</cfscript>
My dependent object's new name is #obj1.getObj2().getMyName()#. He he he he he.

Interviewing obj2 again...

Q: Obj2, is that really your new name?
A: Lemme check... Florence...yep!
Lemme check...#obj2.getMyName()#...yep!

I conducted the same interview with objA and objB, and the answers were identical.

My Conclusion
Circular dependencies, in my experiment, are nothing more than providing each object with a proper internal reference to the instance of the other object, in a reciprocal fashion. The fact that I could change the value of a variables-scoped variable in an injected instance of obj2, and that change be visible by obj2 itself from outside of obj1 proves that point unequivocably. Just for fun, I asked one final question of Obj1:

One Final Deep Question for obj1...

Q: Obj1, what is the name of your dependent object's dependent object's dependent object's dependent object?
A: It's name is Florence
It's name is #obj1.getObj2().getObj2().getObj2().getMyName()#


Cool stuff. Remember though, Coldspring is there for you to manage all of this so that you don't HAVE to do it manually. Coldspring can perform even deeper work, too, like injecting individual METHODS into objects on the fly! That's a little thing I like to call Aspect Oriented Programming, or AOP. You should take the time to investigate it.

Doug out.
Posted by dougboude at 2:26 PM | PRINT THIS POST! | Link | 3 comments



Just What IS Circular Dependency?
Circular dependency.

Initially, the phrase invokes visions of things that we naturally know to steer clear of, like infinite loops. If we've come to OO from a procedural world, we've probably been groomed to fear circular dependency in coding, reinforced by having encountered errors that demeaningly declared "Can't resolve circular dependencies, Idiot!". Circular dependency...it just sounds dangerous, doesn't it? Unstable, unpredictable, uncontrollable; without an end and without a beginning, as in the proverbial question of the chicken and the egg. In OO though, circular dependency needn't be a taboo phrase at all.

When you take a look at the natural world (of which Object Oriented methodologies are a rough emulation of), circular dependencies are common occurrences, and actually viewed as good things. I need my job and my job needs me. That's circular. I need my spousal unit and my spousal unit needs me. That's got a roundness to it, too (pun intended).  But, even deeper than the "we need each other" view, circular dependency implies that each of the two are within one another. Kinda like the ol' Frampton song, "I'm in you....you're in meEEeeeee....". A circular dependency in code is exactly the same thing: two objects who depend on one another for something and exist within each other. My user service needs my address service, and my address service needs my user service. We shouldn't be looking for ways to break these guys up! Rather, let us look at their relationship with admiration, because it is a perfectly natural one.

Now, some architects (we're ALL architects to some degree) might hold fast to a rule of "No Circular Dependencies", and rather than have two objects dependent upon one another directly, they'll create a third object to act as the broker between them. Instead of the two objects being injected into one another, those same two objects are instead injected into the third object, who orchestrates how they work together. I wouldn't say this is a bad thing, and in fact probably makes perfect sense to do so in many situations. Bottom line, though, is that we don't have to avoid circular dependency relationships when they do make sense.

All this talk about circular dependencies got me to wondering just how it all works under the covers. For instance, if I instantiate a CFC that needs another CFC internally, how can I do that without having first instantiating the OTHER CFC (who itself needs an instance of the first CFC I haven't instantiated yet!)? And if I DO manage to get instances injected into one another, will they be by ref or by val? In other words, will object 1 have a copy of object 2 inside of it, and my object 2 have a copy of object 1 inside of it? Or, will they both actually be seeing one another real time? Time for an experiment in object dependency! I'll share the results very soon.

Doug out.

P.S. Here is the link to my circular dependency experiment. (http://www.dougboude.com/blog/1/2007/06/Circular-Dependency-Experiment.cfm).  It REALLY helped clear some things up regarding how to "think about" this topic.
Posted by dougboude at 1:33 PM | PRINT THIS POST! | Link | 1 comment