Monthly Archive for July, 2006

CAPTCHA - eeeewwwww

Dave Shuck posted about making CAPTCHA easier on your users this morning.  While I can see the point, CAPTCHA sucks.  I can't even tell you how many times I go to post something somewhere, see a CAPTCHA image and hit the Back button.  It's not that it's terribly difficult to deal with usually, but the the whole premise is flawed.  Though I can say I've had a couple occasions whereit's taken several tries to get right, and I've got good eyes.

Dave makes a good point about capitalization, but my question is why the hell would you make a CAPTCHA case sensitive to begin with?  And it should NEVER contain 'l', 'L', '1′, 'o', 'O', '0′, or any other even remotely ambigious characters.  And the characters should be friggin HUGE so it's stupid easy to read for anything that has visual processing.  In other words, basic visual processing capabilities should be the ONLY requirement.

While I'll admit to having had some spam problems on my blog, I've solved them without CAPTCHA.  It's not terribly difficult.  A combination of form obfuscation and content filters has basically erased all comment spam with zero user impact.  And note also that I use MovableType under the hood, which is a very common blogging platform and therefore has a large number of spammers specifically targetting it because it's so widely used.

Eclipse/Ant Trick

Eclipse has very nice Ant integration, letting you rrun a build file from the context menu all over the place, either via a dialog for selecting the specific target, or using the last/default target.  What I didn't know until today, however, is that you can right click on a target in the Outline view and run that target directly, without having to go through the normal target selection dialog.

If you use Ant, definitely useful.  If not, reenforcement that it's worth a bit of digging to learn about your tools, so you can leverage them most effectively.

CFCDoc

I just got an email from another CF developer looking for the CFCDoc tool that Spike and I wrote a while back.  It's still available on Spike's site, but I've posted it here as well.

In a nutshell, it's a Javadoc-style tool for CFCs.  Unlike Javadoc, it doesn't generate a bunch of static HTML files, but instead builds pages dynamically.  That's good and bad, as you'd imagine, but mostly good.  Spike built the original and I've modified it heavily to add inheritance information, abstract/deprecated support, constructor (i.e. init()) support.

One significant differentiator between it and the built-in CFCExplorer tool is that CFCDoc doesn't instantiate your CFCs (which runs the psuedoconstructor) and can have some nasty side effects.  Instead of using the getMetaData() function (which is what requires the instantiation), CFCDoc just reads the raw CFML off the filesystem and parses it to extract the needed data.  I can't say for certain (because I've never tried), but that also it should run exactly the same on your CFML engine of choice, not just CFMX.

To get started, download the archive, extract it, add a path (absolute or relative) to your CFC directory in the config.xml file (there are examples), and then fire up index.cfm in your browser.  And, no, I don't get paid by the PayPal links that are in there.

Sudoku Anyone?

For my birthday last month, Heather (my wife) got me a book of Sudoku puzzles.  If you like puzzles and haven't tried Sudoku, highly recommended.  Simple and fun.

However, being the good computer geek that I am, I quickly decided that it'd be a heck of a lot easier to let the computer solve them for me.  Note that this is not cheating.  Since the computer can't do anything I don't tell it to do, I'm still solving the puzzles; the computer must exhibit a subset of my Sudoku prowess.  However, it does have far better "bookkeeping" abilities, which is a marked advantage.

I built it as a simple JUnit-driven Java 5 application.  It's pretty basic: 20 types, plus a few nested types.  It leverages the Strategy pattern for implementing strategies, so adding a new strategy is as simple as implementing the Strategy interface (probably by extending AbstractStrategy) and registering the implementing class as a known strategy.

What was particularly interesting, however, was that the program was able to solve one- through four-star puzzles (five stars is the most difficult) with just two simple strategies:

  1. Checking to see if any given unit (a row, column, or block) has only one cell that can contain a given number, which means that cell must contain the number in question.
  2. Checking to see if all cells in a given unit that can contain a given number are also within a second unit, which means the rest of the second unit can't contain the number in question.

I've no idea how difficult the puzzles are in the overal universe of Sudoku, but it was surprising to me that those two simple strategies were so effective.

I should mention that the rule of the game (each number is present exactly once in each block) is enforced by the system itself, and was usually enough to solve the one-star puzzles.  So you might consider the rules themselves to be strategy zero as they are effective in their own right.

AJAX Anti-Example

US Airways has a AJAXy interface for their homepage, but don't follow their example.  Try, for example, searching for the status of flight 8022 (from Philidelphia, PA to Portland, OR) today.  That happens to be the flight my sister and her family are on at this very moment.

You might try entering the flight number (knowing that the flight number uniquely identifies the flight).  Or you might try entering the departing city (hoping to get a list of candidate flights).  Neither works.  You have to enter both.

Once get both pieces of info in, submit the form.  You might try pressing enter, like I did.  After all, you had to type the info in, so your hand is already on the keyboard.  Denied.  You have to either use the mouse to click the Retrieve button, or tab through to it and press enter.

Ok, so now we get results.  Oh, it hasn't left yet, even though it's a couple minutes past the departure time.  Come back in 15 minutes and hit refresh.  Blank form - no results.  What?  Type in the info again and click on the Search button and see that the flight has now left, 13 minutes late.

A little digging and it seems that they don't use any forms or page parameters.  When you "submit" the form, it gathers data from the form fields, sends it to the server with JS Remoting (which sets some session variables), and then does a location='...' to the destination page where the session variables are read and cleared, and the page rendered.

If you're building AJAXy UIs make a note that you're still operating in an HTTP/HTML environment, so follow the rules.  Use forms for forms.  Use page parameters for generating dynamic pages.  Consider common use cases (like refreshing your flight status page) and their implications to your application.  Don't require superfluous data.  And one last nit-picky thing: don't leave half of your homepage blank specifically for rendering error messages in.

A couple things that they did do a good job on: the autocompletion dropdown for departure airport and tabindexing all their form fields.  But in general, very low marks for usability.