Archive for the 'Uncategorized' Category

CFML and Groovy

So As I said in my last post, there's been a lot of talk about integrating CFML apps with other bits.  I've been playing with Groovy and Grails a fair amount (duh), as well has having a lot of conversations about it.  I've been trying to figure out what the best use case is for the different pieces, and here are what I see as the main alternatives:

  1. Use Grails for your whole app stack
  2. Use Grails for your lower stack, and CFML for the view implementation (instead of GST).
  3. Use CFML for your web layer, and Groovy (maybe via Grails, maybe via plain Spring) for the lower layers, including GORM/Hibernate for persistence
  4. Use CFML for the web and service layers, and using Groovy w/ GORM/Hibernate for the data layer.
  5. Use CFML for the whole thing, and just stick in a bit of Groovy as needed, maybe with a partially GORM/Hibernate-persisted data model.

So what's the right one?  My initial feeling was option three, but after a bunch more talking and thinking, I'm now leaning towards number 4.  The service layer doesn't suffer from the same performance issues related to CFC instantiation that the data layer does.  So using CFML (w/ ColdSpring) has few real downsides for the service layer, but it has definite upsides because you can use CFML within the layer.  Better, you still get the huge benefit of Hibernate and POJOs in the data layer, which is where CF really has a lot of problems.

Interesting times to be sure.  Hopefully when I get back from the conference I'll have more time to write some code and really dig in.

Summer….

Here I am just out of the shower, sitting on the back patio with bare feet and a t-shirt, sunset behind the trees, listening to the babbling fountain and some Leaves Eyes', and finishing up a bag of Mother's Circus Animal cookies.  If only I had a fruity drink with a little umbrella in it…

Off to CFUNITED

Tomorrow morning I hop on a plane to CFUNITED in Washington DC.  Four days of learning, chatting, getting far too little sleep, and generally being a programmer geek 24 hours a day.  Even better, Joshua and Koen (two coworkers) are coming as well.  It's been a hellish past few weeks at Mentor, and getting a little decompression will be a welcome change.

My Projects Page

I've just added a simple projects page for the projects that I blog about here.  There you should be able to find a comprehensive list of projects and their updates from my blog.  It's a one-stop shop for the stuff I write.  I've often considered the best solution for managing all that, and decided simplest is best.  It's a bunch of static pages with static links managed via WordPress's page infrastructure.  Enjoy!

Excalibur Constants

I believe I've blogged about Excalibur (an RPN calculator for Win32) before, but I just discovered the wide array of constants that it has built in:

Excalibur Constants

While I can't say that I use many of those numbers in my daily calculations (which are usually either pixels or dollars), the last one is definitely useful.

My FB3 Lite

I was talking to Sandy Clark back at CFUNITED about how I still use a stripped-down FB3 for a lot of projects. She said I should publicize it, so here goes. At it's heart, it's a toolset for designing something that resembles a single-circuit FB3 application, but with some of the niceties (like DO) of FB4/5. I don't have a sample application to show at the moment, but I thought I'd share the framework itself (all 61 lines of it). It's inline at the end of the post, along with a sample switch file.

To use it, you just need to save the code as 'index.cfm' (or whatever) create a 'fbx_Switch.cfm' file in the same directory that has a CFSWITCH block that switches on 'attributes.currentFuseaction'. There are two mandatory CFCASEs it must contain: onRequestStart and onRequestEnd. The do exactly what you'd expect. Finally, the default fuseaction is named "__default_fuseaction__" (two underscores on the ends), so you'll want to define a CFCASE with that value as well, probably multi-aliased to something a little more friendly (like "home"). That's enough to get code executing.

The "tooling" that the framework exposes is quite simple, and I'll sum it up in a few bullet points:

  • a 'self' variable, which is set to "?#fuseactionVariable#=" and can be used for links (e.g. <a href="#self##xfa.logout#">)
  • an 'attributes.originalFuseaction' variable storing the requested fuseaction (or the default if none was specified)
  • an 'attributes.currentFuseaction' variable storing the currently executing fuseaction
  • a 'do' UDF that accepts a fuseaction to execute, and an optional variable name to put the execution output into
  • an 'include' UDF that accepts a template root to execute, and an optional variable name to put the execution output into
  • a 'location' UDF that accepts a destination URL and does a redirect via a HTTP Location header

Content variables for both the 'do' and the 'include' UDFs are append-only, so if you want to overwrite, you have to manually do it with a CFSET in your switch. Also as you'd expect, this is single-directory centric; index.cfm and fbx_Switch.cfm must be in the same directory, and includes must be pathed relative to that directory.

Why did I build such a framework? Mostly because neither FB3 nor FB5 fits the bill for small applications. Both are a bit on the heavy side, with FB5 being the heavier of the two. But at the same time, they both provide some really nice features (again, FB5 providing a larger number). So I wanted the best of both worlds, and I think I got it. My biggest gripe is that the single-directory nature makes it hard to clearly delineate the app from the framework, but that's a relatively minor issue I've found.

While I think any smaller application could use the framework without too many complaints, it does lend itself to apps where the total number of fuseactions is fairly small (duh), you don't want to do MVC inside the front controller (i.e. you want to use a separate backend), you want the dynamic assembly of FB5 (content variables, DOs and dynamic DOs, etc.), and you prefer to do your controller coding in CFML.

Without further ado, here's the code. I'll admit it seems rather dense, particularly on the web without syntax highlighting. But it's really pretty straightforward, and you probably won't ever need to open the file after you save it if you're using it.

<cfsetting enablecfoutputonly="true" />

<cfset fuseactionVariable = "do" />
<cfset defaultFuseaction = "__default_fuseaction__" />
<cfset self = "?#fuseactionVariable#=" />

<cfif NOT isDefined("attributes") OR NOT isStruct(attributes)>
  <cfset attributes = structNew() />
</cfif>
<cfset structAppend(attributes, url) />
<cfset structAppend(attributes, form) />

<cffunction name="do">
  <cfargument name="fuseaction" type="string" required="true" />
  <cfargument name="contentVariable" type="string" required="false" />
  <cfset var oldFuseaction = attributes.currentFuseaction />
  <cfset attributes.currentFuseaction = fuseaction />
  <cfif structKeyExists(arguments, "contentVariable")>
    <cfparam name="#contentVariable#" default="" />
    <cfsavecontent variable="#contentVariable#"><cfoutput>#variables[contentVariable]#</cfoutput>
      <cfinclude template="fbx_Switch.cfm" />
    </cfsavecontent>
  <cfelse>
    <cfinclude template="fbx_Switch.cfm" />
  </cfif>
  <cfset attributes.currentFuseaction = oldFuseaction />
</cffunction>

<cffunction name="include">
  <cfargument name="template" type="string" required="true" />
  <cfargument name="contentVariable" type="string" required="false" />
  <cfif listFind("cfm,cfml,htm,html", listLast(template, ".")) EQ 0>
    <cfset template = template & ".cfm" />
  </cfif>
  <cfif structKeyExists(arguments, "contentVariable")>
    <cfparam name="#contentVariable#" default="" />
    <cfsavecontent variable="#contentVariable#"><cfoutput>#variables[contentVariable]#</cfoutput>
      <cfinclude template="#template#" />
    </cfsavecontent>
  <cfelse>
    <cfinclude template="#template#" />
  </cfif>
</cffunction>

<cffunction name="location" output="false">
  <cfargument name="destUrl" type="string" required="true" />
  <cfheader statuscode="302" statustext="Object Temporarily Moved" />
  <cfheader name="Location" value="#destUrl#" />
</cffunction>

<cfparam name="attributes.#fuseactionVariable#" default="" />
<cfset attributes.fuseaction = attributes[fuseactionVariable] />
<cfif len(trim(attributes.fuseaction)) EQ 0>
  <cfset attributes.fuseaction = defaultFuseaction />
</cfif>
<cfset attributes.originalFuseaction = attributes.fuseaction />
<cfset attributes.currentFuseaction = attributes.fuseaction />

<cfset do("onRequestStart") />
<cfset do(attributes.currentFuseaction) />
<cfset do("onRequestEnd") />

And the sample fbx_Switch.cfm:

<cfswitch expression="#attributes.currentFuseaction#">

  <!--- lifecycle fuseactions --->

  <cfcase value="onRequestStart">
  </cfcase>

  <cfcase value="onRequestEnd">
  </cfcase>

  <!--- normal fuseactions --->

  <cfcase value="home,__default_fuseaction__">
    <cfset include("dsp_home", "bodyContent") />
    <cfset do("lay_default") />
  </cfcase>

  <!--- private fuseactions --->

  <cfcase value="lay_default">
    <cfset xfa.home = "home" />
    <cfset xfa.login = "loginForm" />
    <cfset include("lay_default") />
  </cfcase>

  <cfdefaultcase>
    <cfthrow type="IllegalFuseactionException"
      message="The specified fuseaction (#attributes.currentFuseaction#) is unknown." />
  </cfdefaultcase>

</cfswitch>

Edit: Here's a link to the project page.

Best Sign Ever

After a Day on the Edge

After a day of using my new Edge, a couple thoughts:

  • As expected, the distance/speed measurements are slightly low, because it assumes traveling in a straight line between checkpoints, so you lose a little bit of distance going around corners.  Compared with my "normal" computer that uses a wheel sensor, the error is about 1.5%, though I know the wheel sensor is reading slightly high because of tire compression.  So it's not too far off.
  • The heart rate monitor takes a bit to get itself inline with my heart.  The three times I've worn it, it starts out reading really high (235-240 bpm), and then after a little while figures out that it's really supposed to be in the 165 range and stays there for the remainder of the ride.  Have to experiment with some different positions and see if I can get it to work better out of the gate.
  • Having a pile of concurrent displays is great, and since you get two pages of them, it's even better.  Speed, cadence, heart rate, time and distance on the main one, and then a bunch of summaries (avg speed, avg heart rate, etc.) on the second page.
  • The provided visualization/export tools are lame (surprise), but MotionBased.com's upload agent uses a fantastic data format.  It's XML (surprise again), and it's very well structured.  That's going to be the data format that I use for all my stuff, which is kind of ghetto, but until Garmin provides decent native tools, it'll work.  I'm on vacation next week, and hopefully I'll be able to get the import mechanism all built out so the data's in the database, and then from there, the sky's the limit.

Public SVN Access

To this point I've kept all my personal projects in a private SVN repository, but Joe wanted access to the source of my bicycle dashboard, so I opened it up to anonymous read access at https://ssl.barneyb.com/svn/barneyb/bicycle_dashboard/.  I'll probably end up opening a few other projects as well (like my award winning schema tool, which has some major updates close to release), so stay tuned.

Draggable Routes in Google Maps

The guys a Google have come through again.  Google Maps now lets you drag driving directions around to add custom waypoints on the route, without having to manually enter their address or lat/long.  Aside from being really neat to play with, it lets you easily map a custom route (say, for my morning commute) without having to do a whole bunch of futzing.  This pretty much trumps any custom route plotting stuff I've seen, and linking support will be enabled in my bicycle reporting dashboard shortly.