Aarrgghh!!

Thinking About Code Objectly

I'm not talking about being unemotional about code, which would be "objectively". No, "objectly," I'm talking about code generation. When I first started writing Squidhead, I was writing procedural code to generate my code. After all, it's tempting to think of it procedurally, as code tends to read from top to bottom. One of the breakthroughs for me was figuring out that most of the coding structures I was using can be expressed as objects. I mean the actual code text itself can be expressed as objects. In ColdFusion, this means a CFC.

Let me show you an example of what I'm talking about:

<!---************************************************--->

<!---create--->

<!---This function inserts a single comment record into the database.--->

<!---************************************************--->

<cffunction access="public" name="create" output="FALSE" returntype="numeric" hint="This function inserts a single comment record into the database." >

<cfargument name="body" type="string" required="FALSE" default="" />

<cfargument name="authorID" type="numeric" required="FALSE" default="0" />

<cfargument name="createdBy" type="numeric" required="FALSE" default="0" />

<cfargument name="updatedBy" type="numeric" required="FALSE" default="0" />

<cfset var commentID = "" />

<cfset var results = "" />

<cfstoredproc procedure="usp_comment_insert" datasource="#application.datasource#" username="#application.dbusername#" password="#application.dbpassword#">

<cfprocparam type="OUT" cfsqltype="CF_SQL_INTEGER" variable="commentID" dbvarname="@commentID" maxlength="4" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_LONGVARCHAR" variable="body" dbvarname="@body" value="#arguments.body#" maxlength="16" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_INTEGER" variable="authorID" dbvarname="@authorID" value="#arguments.authorID#" maxlength="4" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_INTEGER" variable="createdBy" dbvarname="@createdBy" value="#arguments.createdBy#" maxlength="4" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_INTEGER" variable="updatedBy" dbvarname="@updatedBy" value="#arguments.updatedBy#" maxlength="4" null="NO" />

<cfprocresult name="results" />

</cfstoredproc>

<cfset results = commentID />

<cfreturn results />

</cffunction>

This is a basic insert function. We've all written this type of function as part of a CFC.

Let's break this down into its properties:

Documentation

<!---********************************--->

<!---create--->

<!---This function inserts a single comment record into the database.--->

<!---********************************--->

Header

<cffunction access="public" name="create" output="FALSE" returntype="numeric" hint="This function inserts a single comment record into the database." >

Arguments

<cfargument name="body" type="string" required="FALSE" default="" />

<cfargument name="authorID" type="numeric" required="FALSE" default="0" />

<cfargument name="createdBy" type="numeric" required="FALSE" default="0" />

<cfargument name="updatedBy" type="numeric" required="FALSE" default="0" />

Local Variables

<cfset var commentID = "" />

<cfset var results = "" />

Content

<cfstoredproc procedure="usp_comment_insert" datasource="#application.datasource#" username="#application.dbusername#" password="#application.dbpassword#">

<cfprocparam type="OUT" cfsqltype="CF_SQL_INTEGER" variable="commentID" dbvarname="@commentID" maxlength="4" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_LONGVARCHAR" variable="body" dbvarname="@body" value="#arguments.body#" maxlength="16" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_INTEGER" variable="authorID" dbvarname="@authorID" value="#arguments.authorID#" maxlength="4" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_INTEGER" variable="createdBy" dbvarname="@createdBy" value="#arguments.createdBy#" maxlength="4" null="NO" />

<cfprocparam type="IN" cfsqltype="CF_SQL_INTEGER" variable="updatedBy" dbvarname="@updatedBy" value="#arguments.updatedBy#" maxlength="4" null="NO" />

<cfprocresult name="results" />

</cfstoredproc>

<cfset results = commentID />

Results

<cfset results = commentID />

Footer

</cffunction>

Once you've established the structure of the CFC, you make these properties into variables. Anything that could be a list is actually an array. So arguments and local variables are actually an array of <cfargument> declarations, as is local variables. You write getter and setters. Actually I tend to write adders instead of setters as I'm just adding content to properties that grow. The getter that I write just concatenates all of the code and outputs it.

Here's the code:

Function.cfc

You can even break it down even further. If you wanted, each <cfargument> could be an object with each attribute being a property. I didn't go that far in Squidhead, but I did break the <cfstoredproc> declaration into an CFC.

This works very well for highly structured code, like <cfcomponents>'s , <cffunction>'s and <cfstoredproc>'s but it can be extended into less obviously structured code like custom tags. I was able to convert most of my procedural code creators to object oriented code creators.

So for whatever that's worth, maybe this can help someone else out there.


February 21, 2007 Posted by Terrence Ryan at 12:37 AM

ColdFusion, Squidhead, Web Development,



Comments

The only thing I don't like about this implementation is that the formatting of the code ends up locked in Function.cfc. For me, this is similar to the debate over custom tags versus CFC's for interface code.

The code ends up being a formatted document that developers will eventually read. I'd be willing to trade performance to make that document format easier to change.

I don't like having to edit string concatenations buried in a cfc function to change the layout of the code, or to change the format of something usually personalized like comment flower boxes.


Posted by: Dave Konopka at February 21, 2007 8:59 AM

Aarrgghh Guy! That's a good point, Dave, and that is why it does break down the less structured the resulting code is. I'd argue that with functions, storedproc's, and cfc's there are a finite set of permutations because there are a finite set of attributes for the code structures. You may quibble over formatting or order of calls, but I think that tradeoff is worth it. With custom tags and cfml templates, one could argue that it isn't.




Posted by: Terrence Ryan at February 21, 2007 9:49 AM

Posted by Who at September 2, 2010 3:04 PM

Post a comment











Remember personal info?