Wierd Performance Issue Resolved!

A couple days ago I posted an article where I showed a really strange problem with CFC performance. In short, when executing many method calls (hundreds or more) on a CFC in the variables scope of a page (or the request scope), the system would bog down, gradually taking longer and longer to execute the method. Place the same CFC in the application scope (or any shared scope) and BAM problem solved, what had taken a couple of minutes to execute now executes in a couple seconds! And really it should execute in a couple of seconds in the request scope as well.

What this indicates is that there was a painters algorithm somewhere in the ColdFusion server. Sean Corfield had initially reported it as a bug, but after tracking it down, it seems like a low priority (assuming Adobe even considers it a bug, which they may not and I wouldn't blame them). Like many of the things we work with, regardless of the initial frustration, the final solution turns out to be something rather simple.

But I'll outline the steps I took to debug it briefly before I get to the solution.

I had initially done some testing with an empty CFC which had a couple of methods but no logic, just to see what the performance of the straight method calls would be, to rule out the possibility of anything else being cause of my problem. And as strange as it sounds, the tick-counts confirmed that indeed, doing nothing other than calling the method in a loop was causing it to bog down. Thankfully, Glenn Crocker offered the solution to put it in the application scope. As soon as I did that, performance reverted to the expected linear growth line.

This was the point at which I decided to post the blog entry partly because it seemed so strange and I figured if other people didn't know about it that they might want to know about it, but also because I wanted to see what other people might have to say about the problem. It certainly could have just been something that others had discovered before and I was just late to the party. It doesn't seem like that's the case at this point although I could still be mistaken.

Aaron Longnion asked for some more details about my environment such as the operating system, CF version, etc. and Sean had also mentioned referencing the article in the Adobe bug report. So of course, eager to provide any information that might be helpful to folks in diagnosis I posted a variety of information about my environment in the subsequent comments. After being unable to think of any better solutions, I figured I would take a back up of my configuration and reinstall the ColdFusion server.

That did it, the problem was solved.

So at that point I wanted to find out if the problem was an issue with my configuration or if it was a corrupt CF8 installation (at least at best guess). So I copied in my JVM arguments to my clean installation and it seems that having reduced the memory (including the permanent generation) and having changed the garbage collection options hadn't been the cause. But now I had a stack of neo-*.xml config files which the server uses to store the various settings from the ColdFusion administrator. In fact, I had two sets - I had one set from before the reinstall and I had a new set representing the default options from a clean installation of the server. So I backed up the default files, then copied my config files from before the reinstall into the working directory C:\ColdFusion8\lib\, restarted the service and tried again. Bang! I'd reproduced the problem.

At this point I knew that my configuration was at fault, I just needed to figure out which configuration caused it. Which settings would produce this behavior? I knew that there had been changes to the neo-datasource.xml for adding my DSNs and I knew there had been changes to neo-chron.xml for scheduled tasks. Neither of those seemed particularly likely culprits. I thought perhaps it had something to do with the general settings or maybe request tuning (although I didn't remember changing anything in that page of the admin).

I decided to open my copy of WinMerge and compare the directories to see just which xml files had been modified before going any further. I skipped by the couple I knew about, looking for something unfamiliar and saw that the neo-drivers.xml had changed, but that turned out to be a red herring as it merely contained some minor changes in the latest full release of CF8.0.1 (confirmed by a version number in the file). And then I stumbled upon neo-monitoring.xml... D'oh!

A while ago I had been trying to use the new server monitor in CF8 to figure out something that had been troubling me (without much luck) and had then turned all the monitoring features off and told myself I would come back to it later. And then I had posted a comment to the cf-talk mailing list in which I had described part of my problem with the server monitor in CF8, namely that it won't allow me to drill down into my CFCs to see where my memory is really being taken up, so the high-level analysis of "there's a bunch of stuff in application.xxx" wasn't very helpful.

Charlie Arehart had sent me an email off-list I think with a URL, but had made a suggestion or two and I figured I'd give it another try, hoping that maybe I had just overlooked something before. That turned out to not be the case as best I can tell, I can still only see "application.xxx #kb" but not drill down into application.xxx.

Apparently however that's where the problem started.

It seems I made the mistake of shutting my notebook down without first turning off memory tracking (which requires monitoring). Several days had passed and it seems the things I'd been working on hadn't run up on this issue until I saw the geometric performance cost of a CFC in the variables scope a couple days ago. By the time I saw that, the server monitor was out of sight and out of mind and so it didn't occur to me to go check and see if it was still enabled.

Looking at the Server Monitor with the neo-monitoring.xml restored, at the top of the display you can see the two red buttons indicating that memory tracking is enabled. Here's a screen-grab for reference:

So for anyone who is concerned about performance of CFCs in the variables scope -- if you're having any problems in that regard, make sure you check your CF Server Monitor and make sure that the memory tracking is turned off. Also as Marc mentioned before, this is not a reason to simply start putting CFCs in the application scope. There are valid reasons for CFCs to live in the variables scope of the page (or the request scope), so you really should just consider the use case and not worry about this with regard to deciding where to place your CFCs.

So to put a bit of a positive spin on my embarassment... ;) there are a couple of interesting things that have come out of this at least for me.

One is that if you ever have a problem that you suspect might be in your CF configuration, you now know that you can test that by backing up your CF config (jvm arguments and then zip-up all the neo-*.xml files in the lib directory), reinstall CF and compare them to the defaults. You might for that matter even like to just take a zip of the xml files after any new installation. That way you always know you have a copy of the defaults to compare against. Hopefully most of your issues won't be that difficult to track down, but as a last resort, this seems to be pretty effective for isolating configuration problems.

Secondly for anyone who's been curious about what precisely the effect of enabling the server monitor's memory tracking might be, this should give you a little more insight. :)

The only final comment I'll make is that although this does indicate that there's a painter's algorithm going on in the request scope as I mentioned before, it doesn't necessarily need a fix. If the folks at Adobe think they can change the behavior easily within their budgets and timelines, then great! But I certainly wouldn't consider that a priority, since you can of course just turn off the memory tracking. Although it does explain why I was recently unable to run the plugin manager with memory tracking enabled. So changing the behavior of the server monitor will help in some specific cases, I just don't see it as being a high priority.

A Strange Issue with CFC Performance

Generally speaking I'm not the first person to complain about performance. My response to performance issues generally is to figure out how well something must perform and then make it fill that need one way or another (often enough with some kind of caching). Which leads me to this article.

A little over a week ago I posted my last article about the potential for using queries as a mechanism for caching content in ColdFusion. The CacheBox project I'm working on is actually more involved than that, being designed to allow the cache to be stored outside the query, but it uses the query as a management tool either way, which makes reporting a lot easier. In my testing the query seemed to perform very well for every operation except the fetch, which was admittedly slower, but after calculating for what I feel are real-world use cases, it seemed even the fetch was reasonably fast enough and there were unquestionable gains in both durability and the performance of all the other operations including the store operation where the query is grown to accommodate new content.

This was great news. So I proceeded to apply this new technique to a couple of CFCs that are going into the CacheBox project. I had actually done a fair amount of ground work on the project by the time I got back to testing its performance and was then met with an odd and somewhat frustrating surprise.

Initially I expected there to be some additional performance cost for wrapping the query in a CFC (or two as the case may be). But I had rather assumed that the basic cost of making method calls on CFCs would be linear. That is to say that I expected the cost of each call to the CFC method to be roughly the same as the last one, irrespective of the number of calls. That didn't turn out to be the case. I was scaling up geometrically as had happened before with the structures. So when making only 100 calls to the store function it executed in about 2.5 seconds (not as fast as I'd have liked), but at only 300 calls to the same function, the cost to execute suddenly spiked to OVER A MINUTE! What?! An increase of 3x volume had produced an increase of 30x the execution cost!

This seemed rather odd to me, as the query had scaled up in a more linear fashion before. So I figured perhaps I had done something wrong in my CFCs. Then it occurred to me that the rather simple (and powerful) ArgumentCollection object we use in ColdFusion is actually a java object under the hood, just like the structure. And in fact, it's behavior is similar to that of a structure, with some additional features. Could it be that creating all those ArgumentCollection objects is what's causing the server to grind down like this?

So I threw together this CFC to test (notice that the method contain no logic, so if there are any performance issues present, they are inherent to the CFC):

<cfcomponent output="false">
   <cfset instance = structNew() />
   <cfset instance.cache = QueryNew("cachename,content") />
   
   <cffunction name="init" access="public" output="false">
      <cfreturn this />
   </cffunction>
   
   <cffunction name="fetch" access="public" output="false">
      <cfargument name="cachename" type="string" required="true" />
      <cfset var record = 0 />
      
      <cfreturn record />
   </cffunction>
   
   <cffunction name="store" access="public" output="false">
      <cfargument name="cachename" type="string" required="true" />
      <cfargument name="content" type="any" required="true" />
      
      <cfreturn arguments />
   </cffunction>
</cfcomponent>

Then I ran this loop to see how it scaled up when the only action being performed was calling a method on a CFC.

<cfloop index="x" list="100,300,1000,3000">
   <cfset agent = CreateObject("component","agent").init() />
   <cfset ticks = getTickCount() />
   
   <cfloop index="y" from="1" to="#x#">
      <cfset agent.store("id_#y#","hello world") />
   </cfloop>
   
   <cfset time = getTickCount()-ticks />
   <cfoutput>
      <div>#x# records = #numberformat(time)#ms (#decimalformat(time/x)#ms / record)</div>
   </cfoutput><cfflush />
</cfloop>

You can see here that all I'm doing is starting with a small number of method calls and then increasing the number of method calls by roughly 300% on each iteration of the loop. Then I'm calling the method the specified number of times with a couple of arguments and timing the results. (And I made sure that I disabled debugging and robust exceptions in the CF Admin before I tested this, knowing that they can inflate performance costs.)

Here is the end result of that test:

100 records = 63ms (0.63ms / record)
300 records = 469ms (1.56ms / record)
1000 records = 9,328ms (9.33ms / record)
3000 records = 154,844ms (51.61ms / record)

Bam! As I suspected, the basic function calling by itself is scaling up not in a linear fashion like I wanted, but in a geometric fashion like I thought after I started testing.

I have to hand it to Glenn Crocker. Somebody figure out what that guy's drinking, 'cause I want some! He provided an instant solution. And although I could say "that's dumb, that shouldn't be the solution" (because it is, and it shouldn't), right now I'm just happy that it works. :)

The answer?

Put the agent CFC in the application scope.

That's it... just change it to a persistent scope instead of running it in the variables scope of the page.

Instantly when I did that, the performance cost of calling the store method changed to this:

100 records = 16ms (0.16ms / record)
300 records = 31ms (0.10ms / record)
1000 records = 110ms (0.11ms / record)
3000 records = 171ms (0.06ms / record)

See that? Linear growth. The performance is consistently an average of about 0.1ms per call to the method.

Apparently when you put a CFC in the variables scope and start calling methods on it, it places those method calls in a stack. And of course as the stack grows (even though it ought to grow and shrink in this loop), the performance of the next iteration of the method suffers.

Which reminds me of something else I saw a little while ago about people struggling with a perceived memory leak in ColdFusion (although they never definitively said they had proved it had a leak, merely that they were almost certain). And again, at the time, the issue seemed to be when CFCs were placed into the variables scope of a page instead of being placed in a persistent scope like the application scope and used from there.

I wonder if anyone else has submitted a bug-report to Adobe for this issue? It certainly feels like a bug to me... although I'm not certain the folks at Adobe would classify it that way. Perhaps they're not expecting people to be making hundreds or thousands of method calls in the variables scope of a page? On the other hand there's nothing in the docs that says you shouldn't be able. And given that you can (easily) from the persistent scopes, why not?

Anyway, as a final note, although the request scope has the same performance issue (you can probably guess why), the only thing that's really needed apparently is for the object to start out in the application scope. If you create a pointer to the object in the variables scope, it will still perform fine. So the following code will also be free of the performance issue:

<cfset application.agent = CreateObject("component","agent").init() />
<cfset variables.agent = application.agent />

A New Model for Caching in ColdFusion (?)

NOTE: There has been new insight into the content of this article which invalidates much of what I originally wrote here. I'm leaving the article untouched for posterity, but I want everyone to know that these results are not definitive. If you're curious, test the code yourself. ;) I will post a new article soon that explains the new information, but don't have the time to do that today.

Caching is something that just about anyone who works with ColdFusion does to some extent... and that's probably true of most programming languages. A little while ago I realized that my own caching routines were a bit primitive and I decided to upgrade them and about that time I also realized that, gosh, the ColdFusion community as a whole is duplicating a lot of effort around this notion of caching. There are several different cache-management projects on RIAForge each with a different bent of course. There's a Java softcache project and not one, but TWO separate memcached projects.

Some of you already know that this inspired me to start working on a caching framework. And yeah, I know I just said we're duplicating a lot of effort, so it sounds like I'm just adding to the problem, but I don't think so. My plan is to create a caching framework that will handle all the use cases handled by the various techniques currently in use and add to that auto-configuring algorithms, so that you don't have to worry about choosing between different caching frameworks or techniques. If it works as planned, hopefully various other frameworks like ColdBox will begin to use CacheBox instead of maintaining their own caching code and the end result will be both a standard and a HUGE time-saver for the ColdFusion community at large.

Okay, that's the background information. Now for the task at hand. In order for me to make this work, I need to find a basic model for caching to use as a foundation on which the various use-cases can be layered.

Most folks who are writing caching routines in ColdFusion environments today are using structures to hold the cache. And most of the time this works. Sometimes it doesn't.

Back in January, Hal Helms reposted an article he wrote about testing our work. In it he mentions a debacle that happened with Toys-R-Us a while back. The developers hired to work on the project had decided to cache all the products in their database, which Hal describes as an "outside the box" solution. Is it?

I don't think the Toys-R-Us programmers were actually doing anything particularly unusual. I've worked on a lot of projects that used that technique, and honestly most of the time it works. It does however fail occasionally under load because of the way structures work. I described the problem specifically not long ago on the DataFaucet blog.

In short, structures are very efficient for small numbers of elements. As the number of keys increase you get collisions and the work that's done to manage those collisions deteriorates performance until the structure actually becomes less efficient than other solutions.

When I say "small", I'm not talking about 10 or 20, I'm talking about hundreds.

But what if you actually do need to cache thousands of something? It could happen. And of course RAM keeps getting cheaper and the underlying Java limitations will continue to expand, making more of that memory available to us. So we may as well explore what's upcoming for us in terms of caching and scaling in the next few years.

In his article, Hal actually hinted at what turns out to be a pretty decent solution. He describes it as an "in memory RDBMS". I think he was imagining something a little different than what I'm creating, but here's the guts of it.

I did some very rudimentary testing today and have found some important differences in the performance of structures versus the performance of queries. The use of queries and query-of-query in ColdFusion seems to be a much more robust model for scaling up with regard to caching.

This is not load-testing. I would love for someone to run a load-testing tool against this code, to give us some better benchmarks, but I don't have the equipment. As a matter of fact, my old notebook is in bad need of being replaced and for that reason I have the memory settings on my JVM tuned way, way down... to like half what the defaults are, maybe less. Because I was almost constantly running over 50% page file usage.

That being said, I wrote a few templates that create either a structure or a query and then populate it with an arbitrarily large number of entries. Each entry contains several items including an id, a hit count, the first and last time the entry was touched, and an object.

I didn't actually create separate objects, I just created one object and injected a pointer to the same object for each record in the query (or structure) to keep my memory consumption down and let me work with larger numbers of entries in the query (or struct). I then output the time it took to generate the query or struct, loop over a fetch operation for each until it reaches 1000ms to see how many fetches I can perform per second.

Finally I perform a purge operation to remove expired cache, which is where I think this gets really interesting. Purging the structure requires us to loop over each individual structure key, but yanking the expired entry is very easy. Using the query allows us to yank many entries at once (without looping over the query), which is much faster. In order to track the hit counts we need to maintain an extra "index" column which just contains the value of "currentrow" and when we yank our expired cache, we have to update the index which then adds to the cost of the purge. So the question is really interesting - is it faster to loop over the structure and purge individual entries or to purge them all and then update the index?

Benefits

Using a query seems to consume less memory and is generally more stable and scales a lot better than using a structure.

At low numbers in cache (10k) the query is usually a little faster to create than the structure although not very much. It's close to one second to create the query (adding each row individually) and close to two seconds average to create the structure, but remember we're talking about 10k records spread out over who knows how many individual requests, so that performance isn't worth mentioning.

Purging the cache is definitely faster with the query in spite of the need to reindex. With 10k records the query purged in about 30ms compared to about 600ms to purge the structure. This was removing an approximate 20% of the total cache and again, given that purging is only likely to happen every few minutes this isn't a huge issue and probably not really worth changing any of our code for even in spite of its being a 200% improvement in performance. I will say that as the size of the cache increased, the query scaled up better also. With 20k records the structure purged in about 2.5 seconds (3x the cost for 2x the volume) whereas the cost of the query purge increased to about 200ms indicating near linear growth (5x the cost for 5x the volume). Remember that with the query, we're able to simply fetch all the records that are still valid via a query-of-query, whereas with the structure we have to loop over the individual structure keys, fetch each key and perform logic on its sub-keys. Apparently that's more costly than rebuilding the query index.

(I actually tried a couple different methods to rebuild the query index and it turns out that the "brute force" method of just looping over the query and resetting the value is the most efficient! And that doesn't change with the size of the query either. That surprised me.)

What surprised me most however was the memory consumption of the structures as they scaled up. They continued to get slower and slower as I expected, I assume for the reasons I described before. As the collisions become more of an issue the problem grows geometrically.

At 40k entries I was just barely able to create the structure in about 23 seconds. That's 10x the cost for 4x the number of entries. Obviously the underlying objects are having some kind of problem functioning under the load and having to do more work. Unfortunately at that point I was unable to perform enough fetch operations to determine how many would occur in a given second because it produced a Java heap "out of memory error" in the middle of the loop. At 50k entries I was unable to build the structure with my JVM settings tweaked down the way they are.

Comparatively, at 50k records the query was still chugging along just fine, handling everything I threw at it. I was able to create the query in about 12 seconds (half the time it took to create 40k entries in the struct).

The query model also provides us with a convenient ability to perform some selective purging very rapidly. Lets say that we've cached a number of different things that are related -- several different views onto a particular object. Now lets say that we modified the object and so we want to manually purge all the cache for that object. If we were using a structure we would have a couple of choices.

One we could loop over the structure incurring the full purge cost each time we make a change or two, we could make the caching mechanism more complex by adding sub-structures and purge the parent. This latter technique (what the onTap framework does currently) causes problems however when we want to see what's in the cache. We can't very easily maintain information about how many items we're caching their hits, or report on that information because of the complexity of the sub-structure. Also sub-structures may degrade performance as well with each nesting level incurring its own penalty.

The query on the other hand solves both problems at once. It allows us to maintain and report on all the statistical information we want about use times and hit counts without adding any real complexity and in addition it actually simplifies a number of race conditions that have to be accounted for with the more complex approach I've been using. If we want to report on the statistical information, generating the report will be much more efficient than any structure-based approach could ever hope to be. And if we want to selectively purge several related items from the cache, we can do that by specifying a pattern to purge, such as "object-type/#id#/%" and then any records in the cache that begin with the specified object type and id can be quickly and easily purged. My caching systems in the onTap framework do that now, but the code for doing it is much more complex than this query approach makes it a lot harder to do any kind of reporting, so I'm really excited about this change personally.

Drawbacks

The only drawback to using the query instead of a structure is seen when performing fetch operations. But given the mountain of benefits I think the performance cost to implement it is worth it. The performance of fetch operations with either solution degrades gradually as the size of the cache increases. The question is how much and is it enough to be problematic.

It takes quite a lot of content actually to make a fetch operation with a structure take any time at all. With 10k records, the structure in my case was performing over 100k fetch operations per second. With the same volume the query was performing about 200 fetches per second. Now if you were to compare that in terms of percentages, it's true that the structure is fetching over 500% faster than the query when there are 10k records.

Realistically however I don't think this is an issue.

An individual page request isn't going to be attempting to fetch thousands of pieces of cache, it's going to be attempting to fetch maybe a dozen or so at most. So if you string together a dozen or so fetch operations, you're talking about a maximum of about 50ms or so for these fetch operations for the entire request. A human eye blinks in about 1/10th of a second. The span of 50ms performing ALL the fetch operations for a given page even under a load of as many as 10k records will be 1/20th of the time it takes to blink. So even with the relatively slow performance of the query fetch, you could perform all the fetch operations for as many as twenty pages in the span of one blink of your eye.

Yes it's true that the structure could perform the fetch operations for a thousand pages in the same time... however... why would that matter? That's way more than you'll ever possibly need. Unless you've got a use case in which you actually need to perform thousands of fetch operations on a single page (which isn't very likely), I don't think anyone will notice. ;) Worrying about the performance of the query-fetch would basically be like worrying that UUIDs aren't unique enough. Sure, you could create an algorithm that produces an even more unique value, but nobody does because nobody has a need for it.

The only way I could see running into an issue with either of them would be to create a UUID for each chromosome in the human genome and then cache an object to represent each one. But at that point you would run out of memory anyway. ;)

As the volume of the cache increases from 10k the query option continues to slow down. At 50k records in my case it was performing only about 70 fetch operations per second (14ms per fetch). Remember however that this was the point at which I was totally unable to even build a structure with that number of entries because the server fell over with an out of memory error after 3 minutes.

Conclusion

So personally I think it's pretty conclusive that in spite of the cost of fetching, the query is a much more robust and useful model for caching than the use of structures that's common in the ColdFusion community. I would however love to hear your thoughts. It's certainly possible there are things I've overlooked. And I'd love for someone to put my code here under analysis with a legitimate load-testing tool. There's a download in the links at the bottom of this article, between "print" and "linking blogs".

Thanks! :)

Content Management (CMS) Plugins

Something I've tried to promote more recently in the community is that much like the other frameworks, the features of the onTap framework can be extended via "plugins". That aspect is not new. What's new about the onTap framework is that the term "plugin" is used to describe a much more powerful entity.

There's a page on the framework wiki that describes this difference in greater detail, but basically in Mach-II, Fusebox or ColdBox a plugin typically consists of what you can fit in a single CFC. So a plugin in those frameworks may be used within your controllers or your views, but generally won't have its own controllers or views. Some examples from the ColdBox Wiki include: FileWriter, Paging and Captcha. You can see that these are tools you might use within an application, but they aren't applications in their own right.

The onTap framework alread has one plugin that falls in this category, it's called TapMCE for a WYSIWYG editor (and admittedly, I'd like to overhaul the idea). But that's not the primary focus of plugins in the onTap framework. The primary focus in the onTap framework is on peer or sub-applications. Currently you'll find that the onTap framework includes a Members onTap plugin which is a security layer, but is also much, much more than that. The Members onTap plugin also includes a sign-up form and login with optional OpenID support, a lot of internationalization work for managing sites or applications where the users speak more than one language, customizable regional information for your company (country, state, city, plus custom regions like "midwest" or "sales territories"), etc.

There's only one other framework for ColdFusion that I know of right now that uses the word "plugin" to describe a similar kind of modular sub-application that can be installed when you install the framework, which is FarCry. If that's more your speed, by all means go get it and be happy! :) I personally have still not found FarCry to be what I want and I don't think that's very likely to change. Although like the onTap framework, FarCry does a lot for you, to me it seems to have an awfully steep learning curve, and it doesn't seem as flexible. But then my understanding of the FarCry framework is still fairly limited while my understanding of the onTap framework is pervasive, so the fact that I find FarCry to have a steep learning curve and haven't found it very flexible may not mean very much.

I will however briefly point out a couple of items that lead me to that thinking. First, while you can create a new type of object in a few minutes using its built-in ORM and Form Tools, FarCry is really not designed conceptually with the idea that you might use anything other than the built-in ORM and Form Tools. And the ORM in itself is very stringent conceptually about the idea of the developer not thinking about the database or really digging into the ORM at all - you're supposed to only think about your data types (events, news, pages, etc.).

Comparatively the onTap framework has a plugin for the far more flexible DataFaucet ORM (which means the core framework doesn't depend on it), and would lend itself easily to including pluguins that use other ORMs like Reactor or Transfer.

While the Form Tools do appear to be pretty comprehensive, I'm not apt to imagine from what I've read of the documentation that they would allow the kind of discrete customization I described in my previous entry about customizing applications with the onTap framework. (Check out the XSL at the bottom.) Or that if you needed customizations to the business model for users and security that they would be nearly as separated or as easy to implement as described in the first half of that same article. To create a custom member (user) component, all I had to do was extend 3 CFCs and add a few lines for new properties and an extra table for storing the custom values. According to the philosophy behind FarCry's FourQ ORM tool, even thinking about putting the custom data in a separate table means you're doing something wrong, because you're thinking about the database. So I'd be darned surprised if I could just extend their user CFC and suddenly have new properties and behavior in the user objects.

My guess is that's the reason why Daemon as a company generates a fair amount of their revenue creating custom versions of FarCry for different organizations... because it wouldn't be so easy for folks to create their own custom versions like I did with DataFaucet and the Members onTap plugin. If it were so easy, if it could be done in a matter of minutes, people would do it themselves and Daemon would be doing something else for their clients. Don't get me wrong, their business model obviously works for them and I applaud their success. Thus far it just hasn't been the tool for me.

But here's the challenge that I started writing this blog entry about in the first place. Right now there are several third-party plugins for ColdBox (as you saw above) and similarly a variety of plugins for FarCry (a CMS tool even being one of them). The developer communities for both of these projects are currently more active than the community for the onTap framework, which is something I intend to change. As I mentioned at the beginning of this article, I've been promoting the idea of plugins for the onTap framework in the community. The plugins themselves are one of the major reasons for developing the framework in the first place, to truly leverage the talents of the community, so that we can each focus on our core business and allow the community to provide all the various ancillary things we need like for example content management (CMS).

Until recently I've been encouraging other folks to get involved and start writing third party plugins. I can of course write my own plugins (as I have already for the several that are available today). But my hope is to really get more people writing plugins to share with the community. That's the reason why there's a web service for fetching the plugins, to make it dead-simple for people to get them. But I'm impatient and I want to see the community grow rapidly... or more rapidly than is happening already. :) So I'm thinking it may be easier for me to start generating more interest in the framework and in the plugins by taking the time to write plugins myself for applications that already exist in the open source community. So my first target for this (and it may have been too large) was to start with a CMS application.

So I picked several open source CMS packages for ColdFusion and am currently looking over the code to figure out how each of them might be implemented as a plugin for the onTap framework. My selection includes (in no order):

I haven't heard anything yet from the folks who created Sava (don't know any names, sorry) or from Oscar Aravelo who created ColdBricks. Jason Sheedy replied to say he'd be interested in having a look once I have a working copy of ByteSpring as a plugin and also mentioned that he hasn't done much ColdFusion work in the past year.

Mark Woods, the project lead for Speck sent me a longer email with a fair amount of information about it, saying that it was originally intended to work with various frameworks but that he's not sure how that turned out in a practical sense. He did also say that he hasn't done much ColdFusion work recently, but I'm encouraged by the fact that he says using it as a plugin was kind of the original intent, even if it hasn't ultimately turned out that way.

On the surface I have very mixed feelings about ColdBricks because of a few of its installation requirements. Some of the documentation for HomePortals (the ColdBricks foundation) sounds promising, but there's a learning curve here that may require some digging to know if it really lends itself.

My thoughts about Sava are similar at this point. Sava is designed to work with any framework that "doesn't need an Application.cfc", ooof! So basically like Fusebox 3 and apparently ColdBox (which was a surprise to me). But it also is designed to allow you to draw in code from those other frameworks. So I'm hopeful that their forethought about integration will be helpful in retooling it to work with the onTap framework, and certainly I think the unique structure of the Application.cfc will help with that as well.

I must admit that I think I was mildly overconfident when I downloaded them... that doesn't mean I won't turn at least one of them into a plugin, but I do think it will require a bit more effort than I had anticipated. I think I was hoping that creating plugins for them would be easy like it was to customize the Members onTap plugin as I mentioned in my last entry. Perhaps I was forgetting that most folks in today's ColdFusion community aren't writing applications with this kind of seamless integration in mind. There are certainly some steps being taken, as you can see from Sava and Speck, but the popularity of this SOA-style integration is still nascent. As it becomes more popular I'm sure our techniques in the community as a whole will improve and this kind of thing will become much easier. :)

(This is also something that's gained a lot of traction outside the CF community, as you can see with things like Adobe working on the Alchemy tool that compiles C++ code to AS3 for Flash or Microsoft's Common Language Runtime (CLR) that allows things like BlueDragon's CFML engine on the .NET platform.)

In the meantime if you have any thoughts about these CMS plugins I'd be glad to hear them! Or if you have any thoughts about other open-source applications you'd like to see integrated as plugins, just drop me a note and I'll have a look. I may go back to RIAForge and do something like Ray's Soundings polling tool first, that may be a bit easier. :)

How to Customize An Application

Today's been an interesting day for me.

I found myself rereading this old blog entry from Jason Delmore from last year. It was about why Adobe doesn't give ColdFusion away for free like PHP or Ruby, which of course people still debate today although there's not really any reason to debate it anymore with there now being three separate free CFML engines in various stages of development (Railo, Open BlueDragon and SmithProject) and an upcoming CFML language standard committee.

Whatever your opinion on the idea of standards or for that matter committees, you can't argue that 2008 was anything but an eventful year for the ColdFusion community. Some of the news is just caching up to us like the announcement of the beta for the new Bolt IDE for ColdFusion. The community spoke and Adobe listened. Announcements regarding the features of CF9/Centaur (such as Hibernate ORM) are of course similarly exciting. And then there have been all the wow events in the community like Railo announcing their becoming part of the JBoss project and becoming free/open-source and Kristen Schofield announcing the free educational licensing for ColdFusion and releasing the evangelism kit that finally arms us with some great information for evangelizing the platform, allowing you to "be your own Ben Forta" as she described in her Max presentation. :)

These are all great things for the ColdFusion community, they will be great things for the CF Open Source community generally and personally I know they will be great things for the onTap framework community specifically as we grow rapidly over the next year or two.

ColdFusion is a bit unusual in the way it does things. Although it's not without its challenges as is the case with any language, CF has often been the first in new areas. Notably, CF was the first server of its kind to connect the web to databases seamlessly and easily over ten years ago when Allaire released the very first version. The onTap framework today is in some ways following in that pioneering spirit and right now I'd like to show you a few specific features that make it truly unique in today's CF open source community.

I had the pleasure recently of helping Eric Jones with a project he's working on called BeALight.com. They're working on a new member-driven application and with all his other commitments Eric didn't have time to put together the Proof of Concept (POC) even in spite of the fact that as applications go it wasn't very complicated. One of the big challenges with building applications in today's environment is that there are all these ancillary things that need to get done. You have to create a user-management system, you have to create a security framework, you have to create a data-access layer for talking to the database. All these things add up and at the end of the day, he just didn't have time to do it all over again for Be A Light at the moment. (And yes, a lot of shops have developed a "baseline" in their favorite framework to work with to speed up that process, but he didn't have one handy.)

So he posted an unusual request to the CF-Talk mailing list. Is there anyone out there who'd like to build the POC for this application gratis? That is... for free... unless of course you know how to pay your bills with kudos. ;)

If it were me, it would have to be something I really believe in for me to get the guts to post that kind of request. And I think it's pretty obvious that this is the case with Eric, that Be A Light is something he's passionate about, otherwise he'd have just let it slide. (There may be money for this project in the future, but there isn't any currently, so he's not getting paid right now either.)

If you read my last blog entry you know that something I'm passionate about is helping others. While I may not have the kind of religious convictions that Eric has (I'm Unitarian and I think he's Protestant, possibly evangelical), I'm grateful for the opportunity to help someone else in need. And while I enjoy being philanthropic, I also try to be shrewd, so you can bet that I planned to write this blog entry from day one. ;) So the Be A Light POC is actually helping me fulfill several of my goals. I'm helping people and at the same time I'm getting a great opportunity to evangelize the framework platform.

The onTap framework or one of its plugins already handle a number of the things described in the functional spec. A lot of the requested profile information for example name, bio and gender were already implemented in the Members onTap plugin. And so by installing that plugin from the web service, I was able to get much of the way to a working prototype in the first five minutes of development.

Some of the things described in the functional spec however were new and so I had to find a way to integrate those new ideas into the framework. They wanted to handle password retrieval with a secret-question/secret-answer pair (which you may have seen in some other applications), and they wanted several additional fields that would appear on the profile page.

Something I've tried to mention often in the community is the notion that in order to "future-proof" our code, we need to find a way to create applications that can be customized without editing the original application code. Why is this important? Well although I'm sure Eric will maintain Be A Light for a long time, I'm also willing to bet that there will be more future releases of the Members onTap plugin. If I had simply gone into the member form and started adding input fields at the bottom, that would be the "lazy way" of customizing his application. I would be trading the expediency of getting it done quickly and easily in exchange for ... leaving Eric TRAPPED IN TIME! Muahahahaha!!!!

Yes I'm being a little melodramatic to make my point. :) If I were to take the lazy way of customizing the application, I would be editing a file from the Members onTap application, and that would mean that the moment I change even one line of code for a new version anywhere in the plugin, Eric has a problem. Editing that template in his copy makes him out of sync with the plugin core, just like happens when you branch a project in your version-control application. So just like branching, we want to keep that to a minimum. Luckily for me the framework and its plugins save me a lot of time in other areas, which frees up a lot of extra time for these customizations.

Here I'll be showing you how I added Eric's customizations to the Members onTap plugin without changing a single line of the plugin code.

I started with the model. The plugin already has a "member" object with an associated profile view. So I should be able to use the existing form and the existing profile view from the plugin, I don't have to create new ones. The form and the view both make use of the same member.cfc object from the model, so that's where I started my integration.

In order to add our new properties to the member object without modifying the member.cfc directly, I need to use an object-oriented technique. Tada! Inheritance to the rescue. Inheritance lets us use the existing class properties and behavior and add our new features in addition. So I need to extend the member.cfc to create a custom component for our Be A Light project. So there's my first goal.

One of the things that helped me to achieve this first goal is the onTap framework's new IoC manager which manages multiple IoC factories for different plugins. So in this case the Members onTap plugin uses a simplified IoC factory class that's part of the onTap framework core. When you install the plugin, it creates a config file in /_tap/_config/ioc/membersontap.cfc. This is where the IoC container for the member plugin is declared. It looks like this:

<cfcomponent extends="config" hint="configure the Members onTap container">
   <!--- requires the datafaucet container - this line may not be necessary,
   but it shouldn't hurt anything, so I'll put it in here anyway --->
   <cfset loadAfter("datafaucet") />
   
   <cffunction name="configure" access="public" output="false" returntype="void">
      <cfset newContainer("MembersOnTap").init("plugins.membersontap.iocfactory") />
   </cffunction>
   
</cfcomponent>

Pretty simple isn't it? Components in the /_config/ioc/ directory are loaded when the application loads and they configure the IoC containers for individual plugins. So all the business objects for the Member plugin will be in the "MembersOnTap" container created there. The newContainer function creates a new container and allows me to initialize it with the path to my IoC factory which in this case is "plugins.membersontap.iocfactory". Then once the application is running any time I need a member object, I can get it from the MembersOnTap container... That's the simple answer - it actually involves one more object and that's the MemberFactory which is responsible for caching member objects. However, I get the MemberFactory from the IoC container, so ultimately all my business objects for the plugin are coming from that container.

In order for me to swap out the existing member.cfc with our new custom member component, I have to first swap out the MemberFactory object and to do that I have to first swap out the IoC container. Is it sounding complicated? It's not. In fact, by design it's VERY SIMPLE. :)

  1. New IoC Container
  2. New IoC Factory
  3. New Member Factory
  4. New Member CFC

I also know from the spec that the Be A Light project will need some other new business objects to represent messages between users and a few other things. So my plan here is to actually make the Be A Light IoC factory an extension of the MembersOnTap IoC factory and then use that as a substitute. This is beautiful encapsulation, because the rest of our application will have no idea that anything has changed. :)

I start by creating the config CFC for the Be A Light project in the same directory, /_tap/_config/ioc/bealight.cfc. That component looks like this:

<cfcomponent extends="config" hint="configure the Be A Light IoC Container">
   <!--- we're going to override the members onTap IoC Factory with the Be A Light factory,
   so we need to attach it after the plugin loads --->

   <cfset loadAfter("membersontap") />
   
   <cffunction name="configure" access="public" output="false" returntype="void">
      <cfset var container = newContainer("BeALight").init("cfc.bealight.iocfactory") />
      <!--- now we can attach our new Be A Light container also as the Members onTap container,
      so this container will occupy 2 name-spaces in the manager, "bealight" and "membersontap"
      -- "MembersOnTap" has effectively become an alias for "BeALight". --->
      <cfset addContainer("MembersOnTap",container) />
   </cffunction>
   
</cfcomponent>

You might notice that this config CFC looks rather similar to the one for the MembersOnTap plugin. At the top I tell it that it needs to load after the MembersOnTap config loads, so that when I call addContainer() at the bottom of my configure() method, it will override the original Members onTap IoC container with our new Be A Light container.

That's step 1 (IoC Container) done.

Then I need to create our Be A Light IoC factory. That file is in /_tap/_cfc/bealight/iocfactory.cfc and looks like this:

<cfcomponent displayname="BeALight.IoCFactory" extends="plugins.membersontap.iocfactory" output="false"
hint="defines the object model for Be A Light as an extension of the Members onTap plugin to allow some custom member profile information">

   
   <cfscript>
      // we're overriding the member plugin member factory so that we can       // seamlessly integrate the Be A Light profile properties with the member object       // for that we need to override the member factory and the member gateway       define("memberFactory","cfc.bealight.memberfactory");
      define("memberGateway","cfc.bealight.profileGateway");
      
      define("guideGateway","cfc.bealight.guidegateway"); // this gateway is specifically for searching guides and will exclude seekers from the results       define("conversationGateway","cfc.bealight.conversationgateway"); // fetches the subjects of conversations for a given member       define("messageGateway","cfc.bealight.messagegateway"); // fetches the messages associated with a given conversation       
      define(beanName="conversation",beanClass="cfc.bealight.conversation",transient=true); // contains messages and sends emails       define(beanName="message",beanClass="cfc.bealight.message",transient=true); // contains message content and nothing else    </cfscript>
   
</cfcomponent>

Pretty simple isn't it? At the top you can see that it extends the component "plugins.membersontap.iocfactory". If you remember from the first code sample, that's the path to the original IoC factory from the Members onTap plugin. So all we're doing here is extending that factory and we're declaring a few new business objects as well as overwriting the memberFactory and memberGateway objects from the member plugin with our new custom versions. I won't show code for the gateway object, but I assure you, it's as simple as these other files. :)

The IoC factory is so easy to tweak this way in part because it doesn't use an XML configuration file like ColdSpring. If it had used XML this would be a lot harder because I couldn't just extend the factory and overwrite those declarations. ColdSpring is also an option (as is LightWire) and there's a built-in ColdSpring adapter in the framework if you need or prefer it, but it wasn't needed for the member plugin so this keeps things simple. :)

That's step 2 (IoC Factory) done.

So with our new IoC factory for managing our business objects, we need our new custom memberFactory.cfc and member.cfc components. Remember that a custom member object is our ultimate goal, so that we can add the new properties needed to support the Be A Light project. For that we now create our custom memberFactory.cfc which you can see declared in the last code sample above as "cfc.bealight.memberfactory" and of course is located in /_tap/_cfc/bealight/memberfactory.cfc. It looks like this:

<cfcomponent displayname="BeALight.MemberFactory" output="false"
extends="cfc.membersontap.memberfactory" hint="provides object caching for member objects - overrides the default member factory from the Members onTap plugin">

   <!--- this is all we need to do to override the default member class with our new class for members --->
   <cfset classPath.member = "bealight.profile" />
</cfcomponent>

Could it get much simpler? :) If I didn't have the foresight to set that as a private variable within the CFC this might have been a little more complicated, but I anticipated that some people might want to customize the member object, so this file is a cake walk. :)

That's step 3 (Member Factory) done.

In the last step we've declared where our new member object is located in "bealight.profile" we need to create our new member object. Normally this would be "cfc.bealight.profile", but the memberFactory was written to assume the "cfc" directory, so this file will also be in /_tap/_cfc/bealight/profile.cfc and looks like this:

<cfcomponent displayname="BeALight.Profile" extends="cfc.membersontap.member" output="false">
   <cfproperty name="profileJob" type="string" required="false" length="1000*" />
   <cfproperty name="profileSchool" type="string" required="false" length="1000*" />
   <cfproperty name="profilePast" type="string" required="false" length="1000*" />
   <cfproperty name="profileWalk" type="string" required="false" length="1000*" />
   <cfproperty name="profileHobbies" type="string" required="false" length="1000*" />
   <cfproperty name="profileActivities" type="string" required="false" length="1000*" />
   <cfproperty name="profileGroups" type="string" required="false" length="1000*" />
   
   <cfproperty name="secretQuestion" tyupe="string" required="true" length="250*" />
   <cfproperty name="secretAnswer" type="string" required="true" length="250*" />
   
   <!--- all the properties declared here will be added in a 2nd table that's added to the tap_member table data,
   making the merger between the Be A Light Profile and the default Member Object pretty seamless --->

   <cfset addTable("bal_profile") />

   <cffunction name="getLanguageTable" access="private" output="false" returntype="string">
      <!--- in retrospect, the member object could have handled this function better --->
      <cfreturn "tap_memberlanguage">
   </cffunction>
   
</cfcomponent>

Viola! We have our custom member object. I was originally thinking that it might automatically install the new "bal_profile" table from this new CFC but that wasn't the case. (That's an area where I can improve DataFaucet later.) So I did have to create the new database table myself. However at this point member data for the Be A Light project will actually be stored in two separate tables, the tap_member table which was installed by the Member plugin and the bal_profile table we just created to hold these extra values. This contains (but does not eliminate) the threat of future name-space collisions.

The only snag here actually was that function at the bottom, the getLanguageTable() function that returns the name of the table where a member's spoken languages are stored. I discovered after I started testing that it couldn't find the table because the returned table name was wrong due to the customizations. It could have been better written probably, but for now all we need to resolve the issue is to override the function with the proper table name. A future version of the Members onTap plugin will of course remove this minor issue. :)

That's step 4 (member.cfc) the final step in our first leg of customization.

Okay, so the business objects are taken care of, we're half-way done. The remaining tasks are to modify our views and controllers so that the member form and the profile page will show our new properties. Again, the goal here is for every file we use to make these customizations to be what? NEW files. We're not allowed to edit any existing files. We can look, but we can't touch, because touching them is a cardinal sin! :) We do this to keep Eric from becoming TRAPPED IN TIME! Muahahahaha!

Fortunately the framework's templating system and XSL skins provide us with a simple way of accomplishing this task. We'll start with the form. We'll need to modify our controller to inject our XSL into the templating system. So we look in the Member plugin and we see that the member form is in /_tap/membersontap/member/form/. As with most of my applications, the bulk of the controller work is done in the /_local subdirectory. Here we find 100_skin.cfm and 200_form.cfm. This gives us a natural location to add our XSL for be a light between the skin declaration and the inclusion of the form. So we create a file named 150_bealight.cfm that looks like this:

<!---
   member form tweaks for Be A Light are in the be a light skin directory
   -- this provides support for the added member profile settings including secret question
--->
<cf_translate file="#expandpath('/inc/bealight/memberform.txt')#" overwrite="false" />
<cfset arrayPrepend(request.tap.getHTML().skin.memberform,"bealight/memberform.xsl") />

Here we're prepending the "memberform" skin (which is an array of paths to XSL files) and we're adding our new XSL template for the Be A Light project. Above that you can see the CF_TRANSLATE custom tag, which we're using to read a new resource bundle containing the labels for the new input elements we're adding to the form. The resource bundle is the simpler of these two files - it's just there to hold localized strings so that the member plugin can be translated into different languages as needed. The bundle file which is located at /_tap/_includes/bealight/memberform.txt looks like this:

%tap_inputProfileJob=My Job
%tap_inputProfileSchool=My Education
%tap_inputProfilePast=My Past
%tap_inputProfileWalk=My Walk
%tap_inputProfileHobbies=My Hobbies
%tap_inputProfileActivities=My Activities
%tap_inputProfileGroups=My Groups

%tap_inputSecretQuestion=Secret Question
%tap_inputSecretAnswer=Secret Answer

That's pretty normal for a resource bundle. The only thing that may stick out here is that I've prefixed all the variable names for my localized struings with %tap_. That's only necessary here because it's a naming convention I've used in the Member plugin to help prevent potential name-space collisions (and to make it obvious if I forgot to translate something).

The XSL sheet is a little more involved. I would still describe this as relatively easy, although I admit that many ColdFusion developers may not be as familiar with XSLT. Anyway, the XSL file is located at /_tap/_includes/skin/bealight/memberform.xsl and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:tap="xml.tapogee.com"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

   <xsl:output method="xml" indent="no" omit-xml-declaration="yes" />
   
   <!-- copy everything in the source XML -->
   <xsl:template match="*">
      <xsl:copy>
         <xsl:copy-of select="@*" />
         <xsl:apply-templates />
      </xsl:copy>
   </xsl:template>
   
   <!-- add the secret question and secret answer inputs to the login tab -->
   <xsl:template match="tap:tab[@id='memberlogin']">
      <xsl:copy>
         <xsl:copy-of select="@*" />
         <xsl:apply-templates />
         <input type="text" name="secretquestion" tap:required="true" />
         <input type="text" name="secretanswer" tap:required="true" />
      </xsl:copy>
   </xsl:template>
   
   <!-- add the new profile input elements to the identity tab -->
   <xsl:template match="tap:tab[@id='identity']">
      <xsl:copy>
         <xsl:copy-of select="@*" />
         <xsl:apply-templates />
         <textarea name="profilejob" cols="50" rows="8" />
         <textarea name="profileschool" cols="50" rows="8" />
         <textarea name="profilepast" cols="50" rows="8" />
         <textarea name="profilewalk" cols="50" rows="8" />
         <textarea name="profilehobbies" cols="50" rows="8" />
         <textarea name="profileactivities" cols="50" rows="8" />
         <textarea name="profilegroups" cols="50" rows="8" />
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

You may notice that we're creating input elements and textareas here but we're not giving them any values. That's fine, the framework will actually populate all the form fields for us, so we don't have to worry about adding values to our input elements. Also since we added our new properties to the existing member objects, the framework will populate the values for us automatically from our custom member object.

Even on the back-end when the form is submitted it will also automatically update our new table that holds our custom properties because we customized the business object for members. Did you notice how many lines of SQL we edited to do that? Pretty close to zero wasn't it? In fact, it is zero. :)

So at this point, with just these three files shown above, the member form is fully customized! I'm going to skip showing the code for customizing the profile display or the sign-up form in part because this article is already pretty long, but also because the code is very similar to what I've already shown here. There are a couple more controller templates, a couple more XSL templates and one more resource bundle. But as is often the case with frameworks, the structure is basically the same.

So we achieved our goals. We added several properties to a custom member object, we modified the form so that users can edit those new properties and we internationalized the view. Most of the work was basically done for us by using the cfcomponent tag's extends attribute to inherit properties and behavior from components that already existed. Most importantly while doing all this we future-proofed the Be A Light application by ensuring that we created our customizations entirely in new files. As far as I know, the onTap framework is currently the only framework for ColdFusion that makes this kind of future-proofed customization possible.

There is still work to be done on this project and I know that I'll be involved in the continued development, maintenance and support. I'm really happy with how well the integration has turned out and I know I'll be proud of this site. In addition to what I feel is a pretty slick integration, this project was also done on a pretty short timeline. I had a little over a week to get it done and managed to get most of the items in the functional spec implemented. I must admit I ran behind because I added a little much of my own extra code for managing phone numbers, but that's really about me, not about the framework. There's an old saying "good, fast and inexpensive: pick two". This project showed that with the right libraries, it is possible to do all three. ;)

I'm looking forward to hearing your thoughts!

Pay It Forward

What's your passion?

Software is one of my passions, but I'd also like to talk about another of my passions... one that's far more important than software.

Films that inspire thought aren't very common in Hollywood. Films that inspire action are rarer still. Today I was fortunate enough to see one such powerfully moving film: Pay It Forward.

I started out thinking it hadn't been released yet... I'm not sure how but apparently I'd been seeing a lot of commercials or trailers for it recently and didn't realize that these commercials were about eight years old, since the film had been released to theaters in 2000. D'oh! So I went to look for it at the local video store and didn't find it in the "romantic comedy" section. It's a drama. D'oh!

The film starts moving very quickly. The plot is already in motion after only the first two scenes and very minimal, dare I say almost non-existent character development. It starts with a simple assignment given by Eugene Simonet to his 7th grade social studies class: think of a way that you can change the world - and put it into action. The students respond with "hard" and "bummer" to which he responds, "how about possible? Is it possible?" In the film, Simonet himself is even somewhat dismissive of the idea, saying that he's not expecting miracles, but occasionally a student cleans up some graffiti before coming to class. The film of course is about something much bigger.

I'm going out on a limb here. Although this is something I do often, it's never easy. Some of you are aware that I've been living with a mild form of autism. If you don't already know, autism makes it very difficult for a person like myself to relate to others, to know what to say as well as when and how to say it. Or more importantly, what NOT to say. That's always been a challenge for me. I sailed through math and science with straight A's in spite of refusing to do homework assignments... I was in the top 2% on both the ASVAB and the GED test (and would have been offered either a nuclear or intelligence rate if not for my GED) and yet... at 35 I'm just now starting to get the remedial "social studies" education I've always needed.

The kind of "social studies" education I need is something you never needed a class for. No one ever told you, but you learned these things when you were ten years old. Then you automaticized them so that you do them now without thinking, in much the same way you don't think about turning the steering wheel when you drive or in all likelihood the placement of your hands when you type. You don't have to think about what not to say or why, because you just know what not to say. It's obvious to you. But while I still remember the formula for the volume of a cone with little effort, knowing what not to say for me involves a lot of effort and I often stumble still. I have to think about these things every time I open my mouth, every time I type a word in this blog.

For many people struggling with my condition, it's simply easier not to interact with others. That's our natural inclination to begin with, to close off and be content with our own company. Most of us have very few friends and for most of my adult life I've had no social support network. It's caused problems for me that most people never have to face and luckily for me things are starting to change. I'm also fortunate that at a fairly young age I realized that I needed to force myself to be more outgoing. Although I'm still not very good at it even today, you can see that I continue to try, like maintaining this blog.

It's also fairly common for people with autism like myself to avoid talking publicly about things that are personal to them. Talking about things that are personal involves risk even for those without autism, so you can imagine that someone who has such a challenge knowing what not to say might simply opt to say nothing at all, particularly when there's personal risk involved.

I hope also to be an exception to that rule of thumb. I try very hard to be approachable. I hope to let others into my life so that you can know me not just as a colleague or an engineer, but as a person. So I'm going to let you in on a bit of my inner life here, in the hopes that this is something that's okay to share. :)

I grew up reading comic books. My best friend in 3rd grade got me hooked on them as well as roleplaying games. That's also how I started illustrating. Comic books are about epic struggles between characters with impossible abilities and similarly implausible goals. Rule the world? Destroy the Earth? Okay, maybe there are a few very rare individuals who actually have these as goals, but generally speaking we consider these people delusional. But in spite of the fact that comic books are about these very inhuman characters, that's not the big reason we read them. The fans of comic books generally continue to be fans and keep buying and reading them because the writers are able to transform a preposterous collection of random and rather flat or "two dimensional" abilities into a believably human character with that third dimension we call "depth".

What gives a character depth? For one thing they need real human emotions. They need to love something and they need to be afraid of something. They also need to be flawed. They need to do the wrong thing... more than once.

It's somewhat ironic for someone like me to be describing comic book characters this way because autistic people are often viewed as lacking depth. There is for that matter a common myth that we actually don't feel emotions.

In a given week there were several occasions that Tiffany said to me "it's funny damn it", because she shared something with me and although I enjoyed it and actually also thought it was funny, I apparently hadn't outwardly responded. I didn't smile or laugh like she hoped. That's a little distressing to her because then she worries that maybe I think of her as naïve or "easily amused" or something. I don't, but it's still a challenge for her to deal with the fact that I don't always provide feedback the way other people do. I don't always chuckle when I find something humorous. Sometimes, but not always.

Someone else recently related a story to me about a guy who calls his friend and says "hey my girl and I split up because I found out she was cheating on me." The guy hopes his friend will say "hey man, sorry to hear it, I'll bring over a couple of beers and we can watch the game." And although he'll grieve more (later in private), at that moment the couple of beers and watching the game is all he really wants or needs. If he's unfortunate enough to call an autistic friend like myself, he's likely to get something all together different. He's more likely to get a fairly estranged phone conversation and maybe a few weeks later some kind of a web application with a database for tracking people who cheat. ;)

These kinds of stories about the peculiar way that we relate to the world contribute to the common misconception that our minds are mechanical like a computer and that we don't experience or understand emotions like fear and love. I can tell you that we do indeed feel emotions. We just don't express them the same way. In the past several years I've been unable to watch movies about superheroes without crying. It's not limited to the high-dollar events like Iron Man or the X-Men movies... I cry at the b-rate movies like Zoom. The Incredibles? I bawl my head off.

I'm not looking for sympathy here. :) I cried several times during Pay It Forward as well... I mention crying in these movies for a couple of very specific reasons, because I'm trying to let you into my world so you can better understand what I'm trying to say about paying it forward. This isn't just a movie. To quote another of my favorite heroes, "Beneath this mask there is more than flesh. Beneath this mask there is an idea... and ideas are bulletproof." To this idea we must add action and resolve.

The main character of Pay It Forward is an 11-year-old kid named Trevor. The kid presents his idea for the social studies assignment: Pay It Forward. He's going to do something BIG for three other people. It has to be something that's difficult and it has to be something they can't do for themselves. Each of these three people must then repay the favor not to him (they're actually not allowed to pay it back), but to three other strangers in their own times of need. If you know anything at all about the theory behind network marketing, you know that the debt grows pretty rapidly. At only the 4th generation it should affect up to 81 people. Other kids in his class unsurprisingly criticize the idea because "it's the honor system and people blow off the honor system". The teacher, Mr. Simonet says his classmates find his idea "overly utopian", but feels differently himself and praises the idea for its originality and potential, calling it "admirable".

Trevor struggles with his choice of actions throughout the film. He often seems to have bitten off more than he can chew and not surprisingly feels that his efforts haven't worked, that he's failed. At one point he is rather depressed, having a conversation with his teacher Eugene Simonet, who says "I'm grading you for the effort, not for results". Trevor doesn't even smile: "I don't care about the grade. I just wanted to see the world change". Why? Trevor's world is pretty awful. His mother's an alcoholic who works two jobs and scarcely has time to spend with him. His father's also an alcoholic who abuses her and who's come and gone over the years. Trevor has every reason to want the world to change. Hopefully your world isn't so challenging. :) But like every other character in the movie or any well-written hero, Trevor is also flawed.

A few years ago I went through a very difficult time in my life... in 2006 to be exact. This was mentioned briefly during the recent CFConversations interview. During that time I gave up one of my passions. I wasn't programming for a while. The problems stemming from my autism had brought me to an ultimate crisis in my life. I'd been in crisis on and off for years for the same reasons and it had all finally come to a crescendo that might have ended me.

The reason I cry at superhero movies is because no matter how bad the situation is in a comic book, the heroes always, always, ALWAYS HAVE FRIENDS who protect them, who pick them up when they're down and who save them in their hour of need. (And god-willing, so do you!) I don't. I never have, and like most people struggling with autism, that's part of what makes me different. That's the reason I cry when I watch these movies. (Although I'm very grateful that this is slowly starting to change in the past couple years, thanks to some wonderful people like Brian Meloche, Rob Parkhill, Ben Nadel, Mark Mandel, Josh Cyr and Kristen Schofield. Sorry if I left anyone out, just trying to throw in a brief thanks to some folks who've helped me out recently. :) )

But as I said, I was in crisis. When we're in crisis there are a couple of ways we can handle the situation. We can break down and cease to function. We can complain (and I certainly have done my share). Or there's a third option. Like the heroes in comic books, we can have a "radiation accident": a transformative event in which we discover our own powers and choose to make a difference and change the outcome in the future.

The characters in comic books are interesting because they're human, but they're also inspirational because like any good fiction they show humanity's potential. No we can't leap over buildings our outrun bullets. What we can do is evolve. One man in the movie, a heroin addict, happens across a woman who's about to throw herself from a bridge. In that moment he asks her to do something for him. He asks her to save his life and in the process he saves hers. As flawed as we are, we have that potential. We can save each other. People do it every day.

Like Trevor, my world has been pretty awful including abusive parents in addition to the autism problems I've already described. I want to change it. More importantly, I'm planning to change it and I'm putting my plans into action. Like Trevor I want things to change in my own life. I want to have more friends and I work at finding ways to make that happen. But also like Trevor, it's not just about me.

One of the things I'm working on right now is an illustration contract for a children's book. The author was looking specifically for an autistic illustrator. There will be a short bio of me in the back of the book and autism research will receive part of the profits. Hopefully as more people become aware of the problems faced by people with autism (both children and adults), things will be different for kids like me. I have difficulty talking on the phone because of the autism and tonight while talking on the phone with my oldest daughter Alex, I discovered that she has that same problem. My younger daughter Calli exhibits even more of the "tell tales" that indicate possible autism. She has plenty of vocabulary but unlike Alex, she doesn't really articulate the problem she has with talking to me on the phone. She wants to talk to me, but then mostly can only tell me that, "I'm sorry, I don't really have anything to talk about". It's the same thing that happens to me. Alex may struggle with it, but like me she forces herself to find something to talk about. I'll do anything I can to help not only my kids, but kids like them around the world.

I know that for my part this isn't just lip service. Everybody knows the old saying, "talk is cheap", because it's easy to pay lip service to an idea. It's easy to say, "I'm going to do something about this" and then never follow through. We have to put these ideas into action. In addition to working on the children's book, I'm also choosing to be very vocal about my condition in general, to make myself an example... maybe even a target. But it's okay, because it's worth it. It's scary and difficult for me to put myself in the spotlight like this and in part that's why I'm doing it: so they won't have to.

But those aren't the only things I'm doing even still. One of the other things that came out of my crisis in 2006 was that I started researching the reasons why "some guys have all the luck and some guys don't". Over the past couple years I've done a lot of research into the effect a person's attitude has on their life. I needed to know for myself that I could change and how I could change. I needed to know what I could do to make things better. I'm still doing the research -- for example, looking forward to reading a new cognitive science book called Mindset by Stanford psychologist Carol Dweck. But I'm also giving that research back in the form of a book called the Optimist's Wager. Why? Do I hope or expect to get rich selling self-help books? Hardly. I'm writing it because I want the world to change. It doesn't matter if it only changes for one person.

And I'm collecting a list of things that others have done for me to pay forward to the world, like the brief mention Kristen Schofield gave me on her blog. I thanked her personally although I didn't tell her about the gigantic traffic spike she created on woohooligan.com that day. ;) Anyway I expect my debt to grow pretty rapidly. :)

This is your homework assignment: think of a way for you to change the world, and put it into action.

And please come back and share your ideas with me on my blog here so I have some moral support. ;)

Minor Updates and a small Announcement

So a week or so ago I published a new version of the framework core with a minor enhancement to improve on the workaround for web-services/onRequest that may resolve the current issues with running the framework on BlueDragon/Railo. At the time I didn't realize that I had introduced a new bug (albeit small) that prevented the onMissingMethod() feature from working, so any page request would require the base template in addition to the process code in the /_tap/ directory. This is true for ColdFusion 7 anyway, but on CF8 you're supposed to be able to omit the base template and let the server automate it (except for index.cfm).

Anyway in the process of working on some integration for a project for Eric Jones, I discovered this bug as well as a couple of other minor bugs in the Members onTap plugin that were introduced since the recent upgrades for new DataFaucet features. The member plugin bugs only occurred if an administrator attempted to edit their own account via the admin area (instead of the member area). Admins aren't supposed to be able to edit their own roles (because they can't add roles they don't already have themselves and shouldn't be allowed to de-permission themselves), so there's no really powerful reason for an admin to use the admin area to edit their own profile anyway. But it ought to work, so I've fixed those bugs as well... one of which resulted in the admin de-permissioning themselves when they saved the form. D'oh! ;)

Also the integration for Jonese's project is going pretty darned well! I've been able to bypass the IoC for the member plugin to introduce a custom member object which extends the default member object and adds a 2nd table with some additional profile information to the member objects for this project. That in itself is something I'm rather happy with because of how seamless it is. :) I'll be posting more blogs later with additional details about how the integration is done, as well as more information about the project itself as an example of the onTap framework and DataFaucet in the wild. ;)

On a more personal note, I honestly don't think that "who's using this framework?" is ever really a good question to ask. I mean... it's not that asking it is a bad thing, but rather that it's simply unhelpful and especially using it to make decisions can be counter-productive. And I'll share briefly the reason why I feel this way.

The Fusebox framework has been around for a good long while now and there are a variety of mixed feelings about it in the community from the die-hard Fusebox enthusiast to the extreme opposite end of people who really just can't stand it. Each of them has their reasons... but what I'm really getting at here is that Fusebox projects are much the same way. I've never been a big fan of Fusebox myself, otherwise I wouldn't have created the onTap framework. ;) But despite my own preferences I'm reasonable enough to acknowledge that of the large number of Fusebox applications there are in the wild, some of them are well made and some of them are poorly made. Whether a given Fusebox application is good or bad depends to a much greater extent on who managed the project and what resources they had available than it does on the fact that they used Fusebox as their foundation.

I expect the same will be true of just about any framework. There are going to be good and bad Model-Glue apps and good and bad ColdBox apps and I'm sure there will be good and bad onTap framework apps. The fact that the framework isn't being used at Wells-Fargo or on the website for the Metropolitan Opera says absolutely NOTHING about the quality of the framework. The only thing it says is that I've done a poor job of marketing it thus far so it hasn't gained traction (and this is shown to be the case in our frameworks survey also, which I'll talk more about later).

That's the larger reason why I'm now focusing a lot of my time and energy toward being more vocal in the community and improving the marketing. And looking for an evangelist to take the reigns some in the marketing department. :)

BOLT!

There's been a lot of talk today about Adobe's release of the new Bolt IDE for ColdFusion.

hmmm... y'know, this movie's due out any day now...

Coincidence? ;)

800 Downloads for the onTap Framework, Woohoo!

Just thought I'd post a brief note to mention that I'm happy to see the downloads for version 3.2 of the framework hit 800 today. Although that may not sound like a huge number, remember that the onTap framework has been on RIAForge for less than a year. That means that in the 11 months since mid-december of last year, there have been an average of about 2.5 downloads per day! That's pretty darned good! Particularly when you consider the rather large amount of time and effort it takes to get buy-in into any technology. :)

I'm still working on the first release of the onTopic forum. It's taking me a little while not because of the objects, but because of the user interface / interaction aspects. The idea behind this forum system does require a slightly different business/object model than a typical web forum, however, the big challenge really is in accomplishing the interface I wanted. It's actually somewhat Twitter-esque in its approach, but I'll let you see that when it's released. ;) If you're interested in a sneak peek of course you can always fetch it from the Subversion repository for the onTopic project.

Also, still hoping to get more participation in this frameworks survey. What helps you get things done and be the best at your job? We want to know! Knowing that will help us build better tools for you! :)

CFConversations Interview

Hey, just a brief note to let everyone know that Brian and Adam have released episode 21 of the CFConversations podcast which was an interview with Yours Trully. I've never met Mr. Trully in person, but I hear good things! :) The interview covers some technical subjects including both of the frameworks I've developed, DataFaucet and the onTap framework although we also talked a bit about my comic strips and about living and working with autism.

Is this Object Oriented (Enough)?

When people look at my code I get a wide range of responses from incredulous to dismissive to excited. I imagine it's not much different for most advanced developers. As I imagine is the case with many skills, although the expert certainly knows more than the novice, experts often disagree. Why? Well because experts "know better".

A novice looks at a piece of code and generally speaking they can't really tell the difference between code that's "elegant" and code that in spite of "getting the job done" will become problematic later. It's the same with a piece of sheet music or an architectural blueprint or whatever... any skill you haven't thoroughly developed leaves you with a knowledge gap where you can't really discern the subtle differences between good and not so good work. And although gaining skill allows you to become more discerning, it often leads to some rather wide disparities of opinion about what constitutes good or not so good work.

In the past week or two the CF community blog-o-sphere has been talking about what it means to be OO or what it means to be good OO or to "simulate OO". Ben Nadel expressed some frustrations about reading articles about accessors and mutators. We've heard more of the tired, old and completely invalid arguments about ColdFusion not being a "true" OO language because of things like the lack of abstract classes or the fact that a CF object isn't equally as efficient as a Java object (which lacks a lot of the behavior of a CF object). And of course just today Pete Bell and Brian Rinaldi published a short debate about the use of OO techniques.

I'm not going to address the notion that we're "simulating OO" instead of writing OO code when we work in ColdFusion, because frankly, those arguments are stupid, based on misconceptions of OO and not worthy of your time. 'Nuff said.

But in bringing up the previous blog posts, what I'd like to point out is th