Extending ColdFusion Components And Its Impact On Page Performance

Posted November 8, 2006 at 2:31 PM

Tags: ColdFusion

It was lunch time and I was curious as to how extending ColdFusion Components affects page processing time and performance. For those of you who don't know, you can "inherit" the functionality of one component by extending it and overriding functionality. Component instantiation has some overhead in ColdFusion so that leads me to think that using extend has even more overhead... but does it.

To test, I created a Girl.cfc and FullGirl.cfc. The Girl.cfc extends Person.cfc which extends AbstractBaseComponent.cfc. The FullGirl.cfc, on the other hand is "God Object" that can do everything that Girl.cfc does, except that it doesn't need to extend anything.

I then ran tests instantiation X number of components of each type:

 Launch code in new window » Download code as text file »

  • <!--- Set the test size. --->
  • <cfset intSize = 1000 />
  •  
  • <!--- Create an array for the girls. --->
  • <cfset arrGirls = ArrayNew( 1 ) />
  •  
  • <!--- Resize the array. --->
  • <cfset ArrayResize( arrGirls, intSize ) />
  •  
  •  
  • <!---
  • Test the performance of components that
  • extend other components.
  • --->
  • <cftimer label="Extend Methodology" type="outline">
  •  
  • <!--- Loop over the size and add a girl. --->
  • <cfloop index="intIndex" from="1" to="#intSize#" step="1">
  •  
  • <cfset arrGirls[ intIndex ] = CreateObject(
  • "component",
  • "Girl"
  • ).Init(
  • FirstName = "Yuu",
  • LastName = "Sekine"
  • ) />
  •  
  • </cfloop>
  •  
  • </cftimer>
  •  
  •  
  • <!---
  • Test the performance of the a GOD component that
  • doesn't need to extend anything.
  • --->
  • <cftimer label="God Object Methodology" type="outline">
  •  
  • <!--- Loop over the size and add a girl. --->
  • <cfloop index="intIndex" from="1" to="#intSize#" step="1">
  •  
  • <cfset arrGirls[ intIndex ] = CreateObject(
  • "component",
  • "FullGirl"
  • ).Init(
  • FirstName = "Yuu",
  • LastName = "Sekine"
  • ) />
  •  
  • </cfloop>
  •  
  • </cftimer>

After a few tests of creating 1,000 instances, these are the results that I got:

Using Extended Components

1: 15,937 ms
2: 16,312 ms
3: 16,312 ms
4: 16,312 ms
5: 16,281 ms
6: 15,765 ms
7: 16,171 ms
8: 15,765 ms

Using GOD Components

1: 16,328 ms
2: 15,718 ms
3: 15,718 ms
4: 15,750 ms
5: 15,827 ms
6: 15,765 ms
7: 16,281 ms
8: 16,296 ms

As you can see, over a 1,000 object instantiations, the GOD object creation was only marginally faster. In fact, the GOD object creation was occassionally slower. I would say that this is a totally negligible difference. This is very good to know. Extending components makes code easier to extend and maintain. It's nice to know this can be done without really sacrificing any performance.

If you are interested in seeing the ColdFusion components that I wrote for this, they are listed below.

AbstractBaseComponent.cfc ColdFusion Component

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="AbstractBaseComponent"
  • output="false"
  • hint="Handles base functionality for CFCs.">
  •  
  •  
  • <!--- Set unique ID for this instance. --->
  • <cfset VARIABLES.InstanceID = CreateUUID() />
  •  
  •  
  • <cffunction name="Init" access="public" returntype="AbstractBaseComponent" output="false"
  • hint="Returns an initialized AbstractBaseComponent instance.">
  •  
  • <!--- Return This reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction name="EqualTo" access="public" returntype="boolean" output="false"
  • hint="Determines if this ">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Comparable" type="any" required="true" />
  •  
  • <!--- Try to compare this object instance to the passed in. --->
  • <cftry>
  •  
  • <!--- Compare this ID to that ID. --->
  • <cfreturn NOT Compare(
  • VARIABLES.InstanceID,
  • ARGUMENTS.Comparable.GetInstanceID()
  • ) />
  •  
  • <cfcatch>
  •  
  • <!--- An error occurred, return false. --->
  • <cfreturn false />
  •  
  • </cfcatch>
  • </cftry>
  • </cffunction>
  •  
  •  
  • <cffunction name="GetInstanceID" access="public" returntype="string" output="false"
  • hint="Returns the instance's unique ID.">
  •  
  • <cfreturn VARIABLES.InstanceID />
  • </cffunction>
  •  
  • </cfcomponent>

Person.cfc ColdFusion Component

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="Person"
  • extends="AbstractBaseComponent"
  • output="false"
  • hint="Handles base functionality for the 'person' package of objects.">
  •  
  •  
  • <!--- Set default properties. --->
  • <cfset VARIABLES.Instance = StructNew() />
  • <cfset VARIABLES.Instance.FirstName = "" />
  • <cfset VARIABLES.Instance.LastName = "" />
  •  
  •  
  • <cffunction name="Init" access="public" returntype="Person" output="false"
  • hint="Returns an initialized Person instance.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="FirstName" type="string" required="false" default="" />
  • <cfargument name="LastName" type="string" required="false" default="" />
  •  
  • <!--- Store arguments. --->
  • <cfset VARIABLES.Instance.FirstName = ARGUMENTS.FirstName />
  • <cfset VARIABLES.Instance.LastName = ARGUMENTS.LastName />
  •  
  • <!--- Return This reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction name="GetFirstName" access="public" returntype="string" output="false"
  • hint="Returns first name.">
  •  
  • <cfreturn VARIABLES.Instance.FirstName />
  • </cffunction>
  •  
  •  
  • <cffunction name="GetLastName" access="public" returntype="string" output="false"
  • hint="Returns last name.">
  •  
  • <cfreturn VARIABLES.Instance.LastName />
  • </cffunction>
  •  
  •  
  • <cffunction name="SetFirstName" access="public" returntype="void" output="false"
  • hint="Sets first name.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="FirstName" type="string" required="true" />
  •  
  • <!--- Set value. --->
  • <cfset VARIABLES.Instance.FirstName = ARGUMENTS.FirstName />
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction name="SetLastName" access="public" returntype="void" output="false"
  • hint="Sets last name.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="LastName" type="string" required="true" />
  •  
  • <!--- Set value. --->
  • <cfset VARIABLES.Instance.LastName = ARGUMENTS.LastName />
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

Girl.cfc ColdFusion Component

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="Girl"
  • extends="Person"
  • output="false"
  • hint="Handles a Girl object.">
  •  
  •  
  • <!--- Set default properties. --->
  • <cfset VARIABLES.Instance.Gender = "Female" />
  •  
  •  
  • <cffunction name="GetGender" access="public" returntype="string" output="false"
  • hint="Returns gender.">
  •  
  • <cfreturn VARIABLES.Instance.Gender />
  • </cffunction>
  •  
  •  
  • <cffunction name="SetGender" access="public" returntype="void" output="false"
  • hint="Sets gender.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Gender" type="string" required="true" />
  •  
  • <!--- Set value. --->
  • <cfset VARIABLES.Instance.Gender = ARGUMENTS.Gender />
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

FullGirl.cfc ColdFusion Component

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="FullGirl"
  • output="false"
  • hint="Handles all the girl functionality.">
  •  
  •  
  • <!--- Set unique ID for this instance. --->
  • <cfset VARIABLES.InstanceID = CreateUUID() />
  •  
  • <!--- Set default properties. --->
  • <cfset VARIABLES.Instance = StructNew() />
  • <cfset VARIABLES.Instance.FirstName = "" />
  • <cfset VARIABLES.Instance.LastName = "" />
  • <cfset VARIABLES.Instance.Gender = "Female" />
  •  
  •  
  • <cffunction name="Init" access="public" returntype="FullGirl" output="false"
  • hint="Returns an initialized Person instance.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="FirstName" type="string" required="false" default="" />
  • <cfargument name="LastName" type="string" required="false" default="" />
  •  
  • <!--- Store arguments. --->
  • <cfset VARIABLES.Instance.FirstName = ARGUMENTS.FirstName />
  • <cfset VARIABLES.Instance.LastName = ARGUMENTS.LastName />
  •  
  • <!--- Return This reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction name="EqualTo" access="public" returntype="boolean" output="false"
  • hint="Determines if this ">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Comparable" type="any" required="true" />
  •  
  • <!--- Try to compare this object instance to the passed in. --->
  • <cftry>
  •  
  • <!--- Compare this ID to that ID. --->
  • <cfreturn NOT Compare(
  • VARIABLES.InstanceID,
  • ARGUMENTS.Comparable.GetInstanceID()
  • ) />
  •  
  • <cfcatch>
  •  
  • <!--- An error occurred, return false. --->
  • <cfreturn false />
  •  
  • </cfcatch>
  • </cftry>
  • </cffunction>
  •  
  •  
  • <cffunction name="GetFirstName" access="public" returntype="string" output="false"
  • hint="Returns first name.">
  •  
  • <cfreturn VARIABLES.Instance.FirstName />
  • </cffunction>
  •  
  •  
  • <cffunction name="GetGender" access="public" returntype="string" output="false"
  • hint="Returns gender.">
  •  
  • <cfreturn VARIABLES.Instance.Gender />
  • </cffunction>
  •  
  •  
  • <cffunction name="GetInstanceID" access="public" returntype="string" output="false"
  • hint="Returns the instance's unique ID.">
  •  
  • <cfreturn VARIABLES.InstanceID />
  • </cffunction>
  •  
  •  
  • <cffunction name="GetLastName" access="public" returntype="string" output="false"
  • hint="Returns last name.">
  •  
  • <cfreturn VARIABLES.Instance.LastName />
  • </cffunction>
  •  
  •  
  • <cffunction name="SetFirstName" access="public" returntype="void" output="false"
  • hint="Sets first name.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="FirstName" type="string" required="true" />
  •  
  • <!--- Set value. --->
  • <cfset VARIABLES.Instance.FirstName = ARGUMENTS.FirstName />
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction name="SetGender" access="public" returntype="void" output="false"
  • hint="Sets gender.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Gender" type="string" required="true" />
  •  
  • <!--- Set value. --->
  • <cfset VARIABLES.Instance.Gender = ARGUMENTS.Gender />
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction name="SetLastName" access="public" returntype="void" output="false"
  • hint="Sets last name.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="LastName" type="string" required="true" />
  •  
  • <!--- Set value. --->
  • <cfset VARIABLES.Instance.LastName = ARGUMENTS.LastName />
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page



Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Kenton
Nov 8, 2006 at 3:06 PM // reply »
1 Comments

I appreciate you showing this, I always had a nagging voice in my head wondering if my making well structured code was secretly crippling performance. No worries now!


Nov 8, 2006 at 4:25 PM // reply »
56 Comments

@Ben,

I can't stress this enough:

Iteration performance tests are worthless.

If you want a true test to see which is more efficient, then you MUST do a proper load test in a proper environment.

How the hell do you know that a some other process running in the background on your machine interfered with these results? You don't.

I'm sorry it sounds like I'm yelling at you, but I can't stand the fact that every single person in the CF community thinks that writing a loop constitutes a true test of performance. IT DOESN'T.


curious
Nov 8, 2006 at 9:38 PM // reply »
12 Comments

Tony,

given Ben's CFC's can you give specifics on how this should be tested instead?


Nov 8, 2006 at 11:27 PM // reply »
111 Comments

Hi Tony,

I agree that load testing will pick up on things that loop testing won't (especially as it relates to multiple thread and garbage collection and the like).

I don't think it is fair to talk about a process causing the disparity, though. That's why Ben ran the test multiple times.

FWIW, would love to see a post some time on best practices on (affordable) load testing for CF. Any postings you'd recommend or would you get a chance to do a quick posting yourself some time? I'd certainly love to learn how to do performance testing properly!


Nov 9, 2006 at 7:25 AM // reply »
6,371 Comments

Tony,

No worries on the tone; I am a fan of knowledge and truth. I would love to know how to test things in a more useful manner... I mean, that's why I do this type of stuff in the first place.

It makes me wonder though, what do you suppose the best use of the ColdFusion CFTimer tag would be? I pretty much only use it for testing in this fashion, but if this is not useful, I don't really see any use for the CFTimer tag. Any suggestions?


Patrick Whittingham
Nov 9, 2006 at 3:00 PM // reply »
6 Comments

Ben -

I've don't get good times from cftimer, so I use the standard way (end time - start time).


Nov 9, 2006 at 3:05 PM // reply »
6,371 Comments

Patrick,

But even regardless of the CFTimer tag and it's times... as Tony says, this type of testing isn't useful (CFTimer or end-start).

So my question is, if only true load testing is useful for performance testing, then what did the ColdFusion team have in mind when it created the CFTimer tag?


Mar 2, 2009 at 4:47 PM // reply »
63 Comments

Any updates on this? I'd love to hear Tony's suggestions.


Mar 2, 2009 at 6:08 PM // reply »
6,371 Comments

@David,

No updates recently. Sadly, over two years later and I'm still not making full use of ColdFusion components. I need to up this effort!


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 7, 2009 at 5:53 PM
Ask Ben: Javascript String Replace Method
You can find here an advanced function that prepared with javascript replace function. This can make the first letters of words, sentences, lines and whatever you define automatically: http://www.m ... read »
Andrew Neely
Nov 7, 2009 at 4:56 PM
A Moment That Touched Me - The Fountainhead
Ben, Glad you enjoyed the podcast. Yeah, the Tank Riot guys can get really chatty during the episodes, but that's part of the charm of it for me. They've covered everything from Nichola Tesla to Cha ... read »
Nov 7, 2009 at 4:43 PM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
Is it possible to make some more MenĂ¼`s ? ... read »
Jill
Nov 7, 2009 at 11:40 AM
How To Unformat Your Code (Like A Pro)
Derek, I think you might be right - sweet! Thanks for the link :) ... read »
Nov 7, 2009 at 11:25 AM
How To Unformat Your Code (Like A Pro)
I think it would be way easier to just use this http://www.logichammer.com/html-formatter/ He just released v3 and it rocks. ... read »
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »