Copy link to clipboard
Copied
Hi All,
I have two cfc files, the first file contain a very large calculation in couple functions. In the second file I have multiple functions and they are using the calculations from the first cfc file. The issue is now performance because I am calling the functions from the first cfc multiple times from the second cfc.
The functions on the second cfc are called from methods in flex passing parameters and the result of each function on the second cfc will be fill an arraycollection.
It is a way to capture the result from the first cfc and use this from the second cfc without multiple calls?
Any ideas in how to improve my performance?
Thanks
Here is an example of my code:
<cfcomponent name="firstComp" output="false">
<cffunction name="getCostCalculation" output="false" access="remote">
<cfargument name="arg_id" type="numeric" required="yes" />
<cfargument name="place_id" type="numeric" required="yes" />
<cfargument name="start_year" type="numeric" required="yes" />
<cfargument name="end_year" type="numeric" required="yes" />
<!--- Many calculations calling the database --->
<cfreturn result>
</cffunction>
</cfcomponent>
<cfcomponent name="secondComp" output="false">
<cffunction name="getFirstCalculation" output="false" access="remote">
<cfargument name="arg_id" type="numeric" required="yes" />
<cfargument name="place_id" type="numeric" required="yes" />
<cfquery name="getYears" datasource="#application.str_dsn#">
select fydp_startyear, fydp_endyear
from myCost
where req_id = #arguments.arg_id#
</cfquery>
<cfset myObj = CreateObject("component", "firstComp") />
<cfset costResult = myObj.getCostCalculation(arguments.arg_id, arguments.place_id, getYears.fydp_startyear, getYears.fydp_endyear) />
<cfquery dbtype="query" name="resultApp">
select someFields
from costResult
</cfquery>
<!--- Many calculations--->
<cfreturn result>
</cffunction>
<cffunction name="getSecondCalculation" output="false" access="remote">
<cfargument name="arg_id" type="numeric" required="yes" />
<cfargument name="place_id" type="numeric" required="yes" />
<cfquery name="getYears" datasource="#application.str_dsn#">
select fydp_startyear, fydp_endyear
from myCost
where req_id = #arguments.arg_id#
</cfquery>
<cfset myObj = CreateObject("component", "firstComp") />
<cfset costResult = myObj.getCostCalculation(arguments.arg_id, arguments.place_id, getYears.fydp_startyear, getYears.fydp_endyear) />
<cfquery dbtype="query" name="resultApp">
select otherFields
from costResult
</cfquery>
<!--- Many calculations --->
<cfreturn result>
</cffunction>
</cfcomponent>
Copy link to clipboard
Copied
bump1
any ideas?
Copy link to clipboard
Copied
Well I'd probably instantiate an instance of firstComp.cfc in the constructor of secondComp.cfc, and the call getCostCalculation() once in the constructor and put the result in the variables scope; that way the other methods within the instance of secondComp will be able to access that one copy of getCostCalculation()'s result.
If you don't want getCostCalculation() to be run in the init(), then wrap a call to it up in secondComp.cfc's own version of that method (although private to secondComp.cfc), and that could have logic thus:
if variables.theData exists
return it
otherwise
call firstComp.cfc's getCostCalculation() method
put the result in variables.theData
return it
/if
Make sense?
--
Adam
Copy link to clipboard
Copied
You are justified in trying to avoid repetition. That is what the D-R-Y(Don't Repeat Yourself) principle advises us to do.
Repetition doesn't only cause a drop in performance. It will make maintenance of your software a nightmare. Repetition means that every change in the code will likely lead to a cascade of changes in other, possibly unrelated, modules. That will all amount to costs.
The code for your functions, getFirstCalculation and getSecondCalculation, are identical! DRY says no to that.
Also, the following object-creation and function-call are repeated in two separate functions. Again, DRY says no.
<cfset myObj = CreateObject("component", "firstComp") />
<cfset costResult = myObj.getCostCalculation(arguments.arg_id, arguments.place_id, getYears.fydp_startyear, getYears.fydp_endyear) />
My suggestion now follows. I would use just one component instead of two. For example, I would rename secondComp to Comp, say. I would copy the code of the function getCostCalculation into Comp, then ignore firstComp altogether thereafter.
I would reduce the code of the functions getFirstCalculation and getSecondCalculation to just one copy. This new function will be called getCalculation. I would let it have a new argument, ordinality, an integer to denote the first, second, etc. calculation. The final result should be something like this:
<cfcomponent name="Comp" output="false">
<cffunction name="getCostCalculation" output="false" access="remote">
<cfargument name="arg_id" type="numeric" required="yes" />
<cfargument name="place_id" type="numeric" required="yes" />
<cfargument name="start_year" type="numeric" required="yes" />
<cfargument name="end_year" type="numeric" required="yes" />
<!--- Many calculations calling the database --->
<cfreturn result>
</cffunction>
<cffunction name="getCalculation" output="false" access="remote">
<cfargument name="ordinality" type="numeric" required="yes" hint="ordinality is 1 for first calculation, 2 for second calculation, and so on." />
<cfargument name="arg_id" type="numeric" required="yes" />
<cfargument name="place_id" type="numeric" required="yes" />
<cfquery name="getYears" datasource="#application.str_dsn#">
select fydp_startyear, fydp_endyear
from myCost
where req_id = #arguments.arg_id#
</cfquery>
<cfset costResult = getCostCalculation(arguments.arg_id, arguments.place_id, getYears.fydp_startyear, getYears.fydp_endyear) />
<cfquery dbtype="query" name="resultApp">
select someFields
from costResult
</cfquery>
<!--- Many calculations--->
<cfreturn result>
</cffunction>
</cfcomponent>