Monthly Archive for May, 2008

FB3 Lite Updates

After 6 months of use in the wild, I decided to consolidate and republish a couple mods I've made to the framework. The core functionality is unchanged, so for background, check my original post from last year. The enhancements, in no particular order, are as follows:

  • Changed the config at the top of index.cfm to use CFPARAM instead, so the framework can be parameterized by calling code.
  • Most significant is the addition of an 'appSearchPath' control variable, which means index.cfm (the core file) and fbx_Switch.cfm no longer have to be in the same directory. This allows you to put index.cfm in some arbitrary directory (probably with svn:externals) and use it from there. It defaults to ".,.." (this directory and the parent directory), but can be set to whatever is needed.
  • Added the context path and script name to the front of the 'self' variable. I realize this breaks the core on non-JEE CFML implementations, but it fixes some weird redirect issues with IE, so I feel it's worth it. If you don't want it, just remove everything before the question mark.
  • Removed defaulting of the empty fuseaction. Now only a missing fuseaction will be set to the configured default.
  • Added CFABORT to the end of the location() UDF. I went back and forth on this one for quite a while (like measured in days) when I was originally writing the framework, and finally decided to leave it out. After using the framework for a while, I've decided that was the wrong decision, so I've put it in there in this version.
  • Added ability to use multiple circuits via the new 'allowMultipleCircuits' control variable. It defaults to true, which means any slashes in your fuseactions will be treated as path segments, potentially breaking existing apps. If you need to use slashes in your fuseactions, set it to false. When true, a fuseaction of "circuit/fusection" will be converted into an include of "circuit/fbx_Switch.cfm" with attributes.currentFuseaction set to "fuseaction". I've intentionally NOT used the dot separator because they are not circuit aliases as in real Fusebox, but are simply path segments. The include() UDF has always had this ability do to it's strictly path-based nature, though it was undocumented.
  • Added some comments to index.cfm.

There is a project page for the framework, as well as Subversion access available. Current utilization (that I'm aware of) is about 15 distinct applications, most of which I either own or am a contributor to.

Design Patterns in Dynamic Langauges

I went to the Portland JUG meeting this evening to hear Neal Ford talk about design patterns in dynamic languages. Unlike Joshua Marinacci a couple months ago, Neal actually seemed to understand what he was talking about, which was a relief. He gave a quick run-through of dynamic vs. static languages (or ceremonial vs. essential, as he says), and then stepped through a bunch of the GoF design patterns, what they're about, and how they're largely irrelevant in Groovy and/or Ruby because the language provides the "pattern" as part of core language constructs.

What I found most interesting was the different ways that Ruby and Groovy do similar things. While I don't know that I've blogged much about it, those who interact with me in meat-space know all about my aversion for Ruby's ghastly syntax. (I swear Matz was drunk when he was doing the initial implementation and decided it should be a design goal to use every friggin' printable character in ASCII.) Seeing some of it's power compared with Groovy gave me some more appreciation for the language, even if it did nothing for it's appeal. Decorator implementations and method interception were particularly interesting.

Bottom line, however, is that design patterns (at least th GoF's) are incredibly relevant to dynamic languages. In fact, I'd say they're more relevant than ever. With "old" langauge (Java, C++, etc. that the GoF book was targeted at), you could either recognize the patterns and leverage their nomenclature, or you could not recognize them, lose a bit of productivity, but not really be too worse for wear. However, with the dynamic languages having many of the pattern implementations built in, you're really stuck if you don't understand the patterns and what they're about, because you can't use the language without that knowledge.

To use my favorite metaphor (carpentry tools), anyone can use a hammer and a chisel bevel the edge of a board (one specific board, mind you, no retries). It probably won't be very pretty unless you're quite skilled, but anyone can do it given time and patience. Give someone a table router and you've got all kinds of potential to hurt yourself, not to mention chances to ruin their one board, but you can do it quick if you know how. If you don't understand how the more powerful tool works, you're going to be in a world of hurt, but if you can leverage it's strengths, you'll be amazingly better off.

So don't skip the GoF book just because you use a dynamic language. You better know it inside out, just ignore the implementation details.

Google Search Update

After converting to Google Search and giving Google a chance to get everything active, ads stared appearing on the results.  That's part of the deal for getting free search, so they were expected, but after seeing them, I realized the layout wasn't too hot.  With both my sidebar and the ads, the top couple search results were crammed into around 250px of horizontal space - definitely not ideal.

Like the obstacles before, the solution was simple.  I added a couple little jQuery snippets to hide the contents of the sidebar (aside from the search widget) and remove the vertical rule.  Then I set the search results IFRAME's width to take up the entire body of the page, rather than just the main column, and it's done.

Like all compromises, it's not without downsides.  Foremost, there is a brief flicker on page load where the sidebar appears and then vanishes.  The markup for the sidebar is also included in the page, so it has to be generated server-side as well as sent over the wire, just to be ignored when it gets to the browser.  However, contrasted against having to go build a custom page template just for the search results page, two lines of JS and a little network overhead seems a cheap price.

Google Site Search

After frustrations with the K2/WordPress search on my site, I've switched to Google custom search.  I'd never really used the built-in stuff, but when I was setting up my project pages, I did a bunch of searching, and it just didn't seem to work very smoothly.  In particular, you have to manually URL-escape your search string (e.g. replace spaces with pluses) for it to work right.

The Google interface is devoid of such issues, of course, and has the added benefit of searching my full domain, not just my blog posts.  I also included my public Subversion repositories in the search scope, though I'm not sure I'm going to leave that.  The high-churn nature of source code repositories makes for often-outdated results.

The integration was a snap: drop the form code in a Text Widget on the sidebar, and drop the results code in the body of a new Search Results page and I was done.  There were three minor gotchas I had to resolve:

  1. The form didn't repopulate with the current search query on the results page.  That was easily addressed with a little JavaScript in the result page body.
  2. The results page IFRAME was too wide for the site layout.  Again, easily addressed with a little CSS in the result page body.
  3. WordPress lists all top-level pages across the top, and I didn't want the Search Results page showing up there, since clicking it doesn't make sense.  Addressed with a little CSS in the search form widget.

Checkbox Range Selection Update

Just a little update to my checkbox range selection jQuery plugin to allow chaining.  I'd forgotten to return 'this' at the end of the function.  Here's the full source, including the mod:

(function($) {
  $.fn.enableCheckboxRangeSelection = function() {
    var lastCheckbox = null;
    var $spec = this;
    $spec.bind("click", function(e) {
      if (lastCheckbox != null && e.shiftKey) {
        $spec.slice(
          Math.min($spec.index(lastCheckbox), $spec.index(e.target)),
          Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + 1
        ).attr({checked: e.target.checked ? "checked" : ""});
      }
      lastCheckbox = e.target;
    });
    return $spec;
  };
})(jQuery);

You can check the project page as well, for full history and updates.

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!

AmazonS3.cfc Update

I've updated my AmazonS3 CFC to include local caching of files. The new source is available here: amazons3.cfc.txt, or visit the project page.  The only public API change from the first version is the addition of an optional third parameter to the init method for specifying the local directory to use as a cache. If you're doing repetitive read operations on S3-stored assets, using the local cache can speed things up significantly, though it is not without drawbacks.

In particular, the CFC assumes that it is the only interface to the S3-stored assets that it is used to interface with. If you use any other mechanism to manipulate those assets (including multiple CF applications), you'll run into issues. The cache itself is the canonical source for cache state, so emptying the cache folder will always revert the CFC back to S3's state if the cache is out of sync.

If you cluster multiple CF instance together, you can still use the local cache, but you must use a single cache for all CF instances. I.e. the cache must reside on a disk shared by all instances, rather than each instance having it's own separate cache. This reduces the performance benefit slightly (since you must use a non-local disk), but it will still be faster than S3.

The CFC exposes a deleteCacheFor() method that accepts a bucket and objectKey pair that can be used for managing the cache outside of actual S3 operations. If you have multiple CF instances that cannot share a single local cache, or for which the network overhead for a shared cache is still undesirable, you can use this method to synchronize the instances' caches via JMS or something. Obviously that's far outside the scope of the CFC itself, but the hook is there to support it. Note that you must delete cache when overwriting an asset on S3, as the local cache will not pick up the change in S3, it will continue to return the old version if it's not cleared.

Prototype's Array.any/all with jQuery

I needed to convert a couple Array.any() and Array.all() calls (from Prototype) to jQuery syntax. Since jQuery doesn't extend the built-in objects with nice functionality like this, you have to fake it. Here's what I came up with. Old version ('images' is an array):

images.all(function(o){return o.status == "ready";})

and the new version:

jQuery.inArray(false,
  jQuery.map(images, function(o){return o.status == "ready";})
) < 0

Array.any()'s equivalent is the reverse:

jQuery.inArray(true,
  jQuery.map(images, function(o){return o.status == "ready";})
) >= 0

Might have to rip the Enumerable and Array extensions out of Prototype for standalone use as well.

Use ColdFusion? Use Java.

If you use ColdFusion (or another Java-based CFML runtime), you should be using Java. There's a reason that CF uses Java under the hood: Java is incredibly powerful. Yes the interface to Java from the CF level is cumbersome and creating hybrid CF/Java applications pretty much costs you CF's RAD capabilities, but there are some real gems in the Java libraries.

On CF-Talk today, someone asked about reversing an array. There's not a built-in function for doing that, but if you remember that CF arrays are just Java Lists (java.util.Vector, specifically), you can suddenly leverage the full Java Collections framework. In this case, the solution was simple:

createObject("java", "java.util.Collections").reverse(myArray);

Want get unique values from an array? Not a difficult problem, but how about this:

myArray = createObject("java", "java.util.ArrayList").init(
  createObject("java", "java.util.HashSet").init(myArray)
);

Want them sorted? Here you go:

createObject("java", "java.util.Collections").sort(myArray);

Yes, there is an arraySort() CF built-in, but it only sorts text and numbers. So if you want to sort an array of Dates, you're stuck. Collections.sort, on the other hand, will happily sort the dates.

This only breaks the surface of what you can do with Java. Obviously you can't leverage this if you have to support non-Java CFML runtimes, but if you developing for a Java runtime (or runtimes), you owe it to yourself to learn a little bit about the Java tooling available to you.  I've blogged about a couple other Java tricks (fast directory filename listings and string builder tricks) in addition to myriad Java libraries that can be leveraged (Batik, Weka, Ant, etc.)

Here's an complete example of the above tricks:

a = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
// reverse it
createObject("java", "java.util.Collections").reverse(a);
writeOutput(a.toString()); // [5, 4, 3, 2, 1, 5, 4, 3, 2, 1]

// sort it
createObject("java", "java.util.Collections").sort(a);
writeOutput(a.toString()); // [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]

// pull unique elements
a = createObject("java", "java.util.ArrayList").init(
  createObject("java", "java.util.HashSet").init(a)
);
writeOutput(a.toString()); // [3, 2, 1, 5, 4]

// unique elements in sorted order
createObject("java", "java.util.Collections").sort(a);
writeOutput(a.toString()); // [1, 2, 3, 4, 5]

Prototype and jQuery

Since I discovered it a few years ago, I've been a big Prototype fan.  It's simple, and gets the job done with a minimum of fuss.  It's not without warts, of course.  I still occasionally forget to put 'new' in front of Ajax.Request, and some of the Ruby-like methods share their lineage's arcane naming.  When it was new, it was the best thing around, and while it now has competitors, it's certainly not lagging behind.

At work, however, jQuery has been adopted as the standard (and I've no power to change it).  The lack of the $() function is annoying; several times I've debated adding this function (or one of various similar ones) to our library:

function $(id) {
  return jQuery("#" + id)[0];
}

I haven't, of course, as it's not the jQuery way.  jQuery also lacks any sort of class assistance, so we still use the Prototype class framework for our class-based JS.  That seems to work fairly well, except for the fact that we have to use two frameworks where one could suffice.

jQuery is not without it's benefits, of course.  The plugin architecture is a nice aspect that Prototype didn't really offer an equivalent of.  It means the core stays lighter (good), but if you want additional functionality you're stuck managing files from a bunch of different projects (annoying).  Event handling is a bit more straightforward, in some ways.  "Magically" acting on collections of elements with a single call (i.e. no .each(function(o){…}) garbage) definitely makes for more readable code as well.

Because of this shift at work, I've been porting some of my personal apps over to jQuery as well.  I've actually been using a couple jQuery plugins (both self-written and external) for specific tasks for a while now, but not the core framework.  What I've found, however, is that jQuery can be prone to slow code.  To avoid a huge amount of extra work on the part of the JS interpreter, using temporary variables for jQuery objects is essential.  If you do strictly id-based queries, the degradation isn't huge, but if you do CSS-based queries, it can be significant.  With Prototype's focus on id-based queries (at least until $$() came about in 1.5), that was less of an issue.

This need to query a minimum number of times can provide a fair amount of complexity when you have more than a handful of closures hanging about and/or a dynamic DOM.  You end up doing a lot of state management work because you're, in effect, caching DOM lookups and have to ensure you never have stale cache.

Other than that issue and the lack of an equivalent to document.viewport, porting has been relatively painless.  Still very id heavy, so not leveraging jQuery as much as could be, but most of what I'm doing wouldn't benefit from other selectors.

Which one is better?  Hard to say.  jQuery seems to make you work harder to type less code, while Prototype seems to cost you a few more characters for a bit less density.  With the exception of Prototype's class support, their feature sets are fairly equivalent, especially with jQuery UI now available to "compete" with Scriptaculous.  For the moment, I'm choosing to use jQuery on new stuff, but wishing for Prototype every few minutes.  Until I come up against some sort of significant wall, it'll probably stay that way, just to stick with the same tooling professionally and personally.  And over time it'll probably get better as the Prototype-ness fades from apps.