David Harris's Technology Blog

ColdFusion, Flex, and other stuff...   (and 341,536 hours, 30 mins in to my plan for global domination)

Search:

Calendar:

Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Subscribe:

Enter your email address to subscribe to this blog.

Archives By Subject:

Tags:

action script adobe air ajax cfug coldfusion flash flex frameworks free software fxug general jpgmetadatareader mac off topic opensource papervision spry

Recent Entries:

No recent entries.

Top Posts:

Recent Comments:

Top Commenters:

My Links:

RSS:


ColdFusion and constants - how do you do them?

I've been working on a project a bit lately and found I've had the need to use some constants.

This has gotten me thinking how to implement them.

When work in Flex, I use the Extensions for Adobe Cairngorm and when creating your custom events involves you declaring constants in the event. The consts in the event are related to the Event type.

The idea behind constants is that this is information that *will never change*, hence the name "constants" :-)

In the CF application I've been working on, UUIDs are used, and there is no way you can call a UUID "human readable", so this can make code harder to understand when you see something like:

<cflocation url="/index.cfm?page=70688909-1676-D9C3-F2C5B9F163AEBDCF ">

If you want the person who reads this code later understand which page that is with out having to pull the application apart (and hair out too sometimes), you might to this:

<cfset uInfoPage = "70688909-1676-D9C3-F2C5B9F163AEBDCF">
<cflocation url="/index.cfm?page=#uInfoPage#">

That way the name of the variable will indicate *what* that UUID value indicates.

With me so far?

"But Dave, my application has more than one template and I don't want to have to do that every time I want to send a user to the info page, and what happens if the UUID of the info page changes?" you cry.

Well, why not have a single "thing" that stores all your constants that you can store in one place and use everywhere?

What I started doing here is I created a "Const.cfc" that had getter functions on them to return the constants. EG:

<cfcomponent output="false">
<cffunction name="getInfoPageUUID">
<cfreturn "70688909-1676-D9C3-F2C5B9F163AEBDCF">
</cffunction>
</cfcomponent>
So the previous code can be done as:
<cflocation url="/index.cfm?page=#oConst.getInfoPageUUID()#">
(to be honest, I'd actually drop the "get" on the function name and just call it "InfoPageUUID", as it is a const and there is no "set", so why "get"?)

(Another note: I'd usually declare/call the function in all CAPS too, as this is the "standard" way of naming constants)

The above relies on "oConst" being created, which could be stored in application scope for example.

What I didn't like about this is that the actual value is hidden from my old friend "cfdump", and if I have alot of constants I can't see their values in one hit.

This lead me to the "this" scope of my CFC(s).

Something like this:

<cfcomponent output="false">
<cffunction name="init">
<cfset this.INFOPAGEUUID = "70688909-1676-D9C3-F2C5B9F163AEBDCF">
<cfreturn this>
</cffunction>
</cfcomponent>

...which them means the example code can be written like this:

<cflocation url="/index.cfm?page=#oConst.INFOPAGEUUID#">

Before you cry "But people can change the values in the 'this' scope and break stuff!", I've always thought if people want to do that, it's up to them, but don't come running to me if it breaks! (Also, CFCs are not secure at all anyway! see related entry)

The two things I like about using the "this" scope for constants are:

  • 1: You can see all the values if you cfdump it
  • 2: If you CFC has functions, you don't have lots of functions to work out that don't really do anything

Let me explain the second point a bit further.

Imagine I have a DB table that stores information of pages on my site. My CFC has functions to work with this data. In my application I have 1meeeeeeelllion UUIDs to do with various parts of the application, that are used in various ways, that would help the readability of my code if they are stored as constants. This would render the "One Constant.cfc to rule them all" a bit hard to manage. What I have been doing is storing the UUIDs to do with that part of the application in the CFC that deals with that part of the application.

EG:

<cfcomponent output="false">
<cffunction name="init">
<cfset this.INFOPAGEUUID = "70688909-1676-D9C3-F2C5B9F163AEBDCF">
<cfset this.HOMEPAGEUUID = "70826CD8-1676-D9C3-F256954C82CAF104">
<cfreturn this>
</cffunction>
<cffunction name="doSomething">
</cffunction>
<cffunction name="doSomethingElse>
</cffunction>
...lots more functions here...
</cfcomponent>

If you create that cfc and dump it as below:

<cfset oMyObject = createObject("component","someCFC").init()>
<cfdump var="#oMyObject#">
by default (CF8 I think...) I would see all my constants at the top and all my functions would be collapsed.

Given the above code uses no frameworks and if any of you managed to read all my brain dump, what thoughts do you have on the above and/or how have you approached ColdFusion constants?

Disclaimer: all the above code is psedo code and hasn't actually been tested, but feel free to point out syntax errors etc. I may change it, I may not...

Related Blog Entries

Comments
We have a solution almost identical to what you are talking about. We had a need for constants so we created a CFC (oCon). Then we just pass that cfc object around to reference the constants. We also just did all of the this.XXXX in the initialization code before the method calls. Then the only functions are display functions to give formatted output of the constants. We have a number of constants and developers were forgetting what went with what.

We have a developer console (dashboard) that will allow you to restart the app, display constant values, etc.
# Posted By Andrew Penhorwood | 4/5/09 2:10 AM
I tend to set constants up in the as a 'pseudo' bean in ColdSpring config using a map. However if I'm not using ColdSpring, then I set them up in the onApplicationStart method of Application.cfc and use the 'allowoverwrite' flag of StructKeyInsert to ensure the value can't be overwritten. Example:
StructKeyInsert( "Application.Constants.HOMEPAGEUUID", "70826CD8-1676-D9C3-F256954C82CAF104", false );
# Posted By John Whish | 4/9/09 8:24 PM
If you wanna be able to dump the consts, store your consts in Variables.instance scope, and write a dump() function that calls <cfdump var="#Variables.instance#">. :)

You can also use ColdSpring with a config bean. ModelGlue has one, that write all the getters for you. see: http://www.dougboude.com/blog/1/2007/06/Global-Con...
# Posted By Henry Ho | 4/17/09 6:46 AM
What about storing all these constants in a database? Then load it into a structure in onApplicationStart()
# Posted By duncan | 4/17/09 8:59 AM
We use the 'this' scope of the related cfc to store constants. I also use the C++ convention of making the constant label ALL CAPS.

<cfcomponent name="catalog">
<cfset this.IMAGE_SMALL = "small"/>
</cfcomponent>

<cfset product = catalog.GetProductBySku(data.sku)/>
<cfset image = product.GetImage(catalog.IMAGE_SMALL)/>

So in this case, we have a component that stores constants that are used by a number of other smaller classes, but isn't global to the entire application. The product component in the example above could have its own constants if appropriate, and the catalog component does more than just store constants.

Other than providing readability, using constants can be a good way to abstract data, such as in the example above where the constant maps to a database key value. There is no guarantee that the data will be consistent from project to project, especially when the data is being imported from a client's legacy system.
# Posted By Jim Connor | 4/20/09 2:08 AM
I should point out that the THIS scope is a public property so can be set by code outside your cfc. For example, a rogue developer could do this to change you constant value:

catalog = CreateObject('component', 'catalog');
catalog.IMAGE_SMALL = "new value";
# Posted By John Whish | 4/20/09 8:43 PM
> I should point out that the THIS scope is a public property so can be set by code outside your cfc.

David already pointed that out in his post, and I share his sentiment. A rogue developer who wanted to sabotage the app would be better off with a statement like:

<cfset StructClear(application)/>

I believe that coding for ease of use, and more importantly, ease of reuse, outweighs the minimal concern for "rogue developers", at least in our environment.
# Posted By Jim Connor | 4/21/09 4:28 AM
Hi Jim, you're right. David does mention that in the post. I read David's post when I posted my original comment, but didn't read it again when I saw yours so thought it was apt to point out (again as it happens!) about "this" being public.

When I said a rogue developer I didn't mean a malicious developer who actually wants to cause damage. I meant one who might change one of the constant values in their code to maybe test something and then either forget to delete the code that sets the value or not realise they have updated an application scoped variable and leave it as the wrong value, rather than a malicious developer who actually wants to cause damage.

Totally agree that for most people, ease of use outweighs the rogue developer concern. As long as people know the pros and cons of each approach then using whichever one suits them best is the way to go!
# Posted By John Whish | 4/21/09 8:29 PM
Hi David,

If you create a getConstants() method where you just set up a local var STRUCT with the constants in it then you can call

this.constants = duplicate(getConstants());

in your init() method. If users changed the object.constants struct nothing would happen. They'd require access to the file. And if they complained about nothing happening you could tell them to look up the the term "constant" on dictionary.com.

But they couldn't break your code at least (don't worry they'll find other ways) .
# Posted By Ben Spencer | 5/23/09 3:53 AM
Hi again,
I must have been taking crazy pills for that last comment (ages ago). Of course the user can change the object.constants scope in their use of the object. What I really meant was that inside the cfc you could continue to use getconstants() and always be sure to obtain the value you intended. Outside, well that's another matter, I would say if you don't want the developers to change values then you make them use getconstants() as a public method if they needed to read a value.
# Posted By Ben Spencer | 8/3/09 9:34 PM