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

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.


Nov 8, 2006 at 9:38 PM // reply »
13 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,516 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?


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,516 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 »
65 Comments

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


Mar 2, 2009 at 6:08 PM // reply »
6,516 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 21, 2009 at 4:49 PM
Styling The ColdFusion 8 WriteToBrowser CFImage Output
Great work yet again Ben! Whilst I didn't use this whole code, I copied some of your regex code for a similar problem with the lack of an alt attribute and unescaped ampersands in CFIMAGE for Railo 3 ... read »
Nov 21, 2009 at 1:13 PM
My First ColdFusion Builder Extension - Encrypting And Decrypting CFM / CFC Files
@Ben, Because I am pedantic, I just want to make sure that everyone knows there is absolutely no encryption going on. There is only encoding and obfuscation. The cfencode tool only obfuscates your C ... read »
Nov 21, 2009 at 12:28 PM
Using ColdFusion Structures To Remove Duplicate List Values
@Jody I can't seem to get your code sample to work. If you are still having problems, try this code out and see if it gets you what you wanted. <!--- Comma delimited list with various duplicates ... read »
Nov 21, 2009 at 11:03 AM
Groovy Operator Overloading Does Not Work In The ColdFusion Context
Hi Ben, Thanks for this informative post. Now I am reading ur old posts too ... read »
Nov 21, 2009 at 10:56 AM
HostMySite.com Has The Best ColdFusion Hosting
@Mehul, Yes very nice people, however several downtimes per day which was not acceptable. Hence we had to move out. I am glad you are having good luck with them so far. ... read »
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »