Skip to main content
Inspiring
June 20, 2012
Question

CF10 reusing cfc functions

  • June 20, 2012
  • 2 replies
  • 991 views

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>

    This topic has been closed for replies.

    2 replies

    BKBK
    Community Expert
    Community Expert
    June 28, 2012

    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>

    jfb00Author
    Inspiring
    June 27, 2012

    bump1

    any ideas?

    Inspiring
    June 27, 2012

    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