Monthly Archive for December, 2004

ColdFusion for Christmas?

I got an interesting email from Tim Buntel (Macromedia's Senior Product Manager for ColdFusion) yesterday.

"We would like to hear more about your BlueDragon experience. If
you could write up a document detailing your experience, frustrations,
and the like, we could help you out with your request for a shiny new
license of ColdFusion MX 7 Standard."

So I might well get a
license of CFMX for myself without actually having to earn all the cash
and send it off to Macromedia.  Nice for me (less work), nice for
Heather (maybe a late christmas present for her), and nice for
Macromedia as well (potentially some free - as in beer - advertising).

Merry Christmas to all, and to all a good night!

TinyMCE

With cross-platform inline HTML editors all the rage these days, I
though it appropriate to share my experiences with a couple of them
this evening.  I use soEditor and HTMLArea
extensively in my professional work, and like them both.  Neither
is perfect by any measure, but they get the job done, though soEditor's
IE-only stance is becoming more and more cumbersome.  However, I
went a totally different track from the known and into the
unknown.  My requirements were very minimal.  Has to work in
IE and FireFox (on Windows, OSX, and Linux).  It needs to easily
allow for custom link and image dialogs.  It needs to load hella
fast, and turning off pretty much everything on the toolbar needs to be
simple too.

First stop was FCKEditor
It's gotten a lot of time on CF-Talk of late, so I thought I'd give it
a whirl.  It's definitely a full-featured editor with all kinds of
features and customizability.  However, I was unable to get it to
do anything except load it's initial blank document in the
IFRAME.  Since I had no issues running the demos on the FCKEditor
site, I suspect that the problem arose from running on BlueDragon's
internal web server.  Unfortunately, until New Atlanta gets around
to releasing an Apache 2 connector for OSX, that makes the issue a deal
breaker for FCKEditor.

The next one I tried was TinyMCE,
which seems to be a lightweight version of a more elaborate editor that
Moxiecode sells.  I'd run across it in the past and was impressed,
particuarly with how lightweight it was, because that's exactly what I
needed.  Threw the directory in my web root, and it fired right
up.  Firefox refused to use the stylesheets because BD was serving
them up with the wrong MIME type, but other than that, it worked like a
charm.  Customization was straightforward, and in less than two
hours, I'd gone from Google to fully implemented, with custom dialogs
and everything.

I would have liked to have played with FCKEditor a little more, as it
seems really slick (though rather slow to load), and mostly gets
glowing reviews, but unfortunately that didn't pan out.  However,
I did find a new editor that is very well suited to lightweight editing
tasks.  It's fast and simple from both user and developer
perspectives, and it looks like it can be scaled up pretty effectively
to meet pretty in-depth editing needs.  It doesn't come with all
the bells and whistles that FCKEditor or HTMLArea come with, but if you
don't need all the extras (or are going to build your own), it's
definitely a good choice.

BlueDragon: Still Breathing Fire

BlueDragon continues to give me fits. CFEXECUTE (which I'm not sure - there is conflicting evidence - is supported on the Server edition) refuses to work correctly. No big deal, since launching a Process direct from the Runtime class is straightforward (I didn't need the IO streams, in this case). However, the waitFor() method of Process refuses to do anything except throw exceptions when called, which basically means no syncronized subprocesses. So what's the solution? Write a JSP page that does the exact same thing (except it works) and then call it with CFHTTP. Hardly elegant, but it worked well enough.

Next problem was doing some simple image manipulation with the ImageIO class (from javax.imageio). Nothing complex, just a simple read-scale-write operation to generate a thumbnail. However, BD pukes on the write part. From the stack trace on the NPE, it appeared that it was having trouble selecting which of the method versions (write is overloaded) to call, even though it was pretty clear cut (the one with a RenderedImage, a String, and a File). What's the solution for this case? You guessed it. Write a JSP page that does the exact same thing (except it works), and then call it with CFHTTP. Ooof.

I do tire of such hacks, and so once again, my pursuit of the CF license is in full swing. I just finished up some more work for Fusium (awaiting the check), and lined up another little project that should just about round out the two grand I need. Now if only I could be done and have the license today….

iTerm Rules

I long ago discovered iTerm, a slick little Terminal replacement for OSX. Among other things, it lets you have tabbed windows, just like any decent browser, which is handy for managing the swarm of SSH and MySQL sessions I usually have open. What I just noticed today was that you can tear a tab off into it's own new window, which is way slick. Only problem: you can't move tabs between windows at will. Regardless, it's a handy feature to a very functional piece of software that no OSX user should be without.

Architecting FB4.1

Architecting with Fusebox 4.1 is a very wide arena. There are lots of ways to do it, but I think I found one that is particularly well suited to the framework, especially when combined with CFCs for a backend. My presentation at the 2004 Fusebox Conference hinted at much of the principles, but I can say that after having written a couple more FB4.1 apps from scratch, that they make for a very nice little package.

There's a few main points:

  1. Separate 'pages' from 'actions'
  2. Separate the UI from the application proper
  3. Separate the markup from the presentation
  4. Reuse code everywhere it makes sense, and nowhere else

For point #1, a legit question might be "what's the different between a page and an action?". My definition is that a page renders content to the user, while an action performs an action and redirects to somewhere else. The definitions are mutually exclusive, so if you're doing an action, you HAVE to redirect to a page in order to render content; you can't do both on a single request. There are a few exceptions (for instance, marking a message 'read' - an action, when you open it - a page), but they are few and far between.

I opted to have all my fuseactions that generate HTML be named as you'd expect (addEntry, viewComments, etc.). All my fuseactions that do actions start with 'do' (doInsertEntry, doDeleteComment, etc.). In my presentation at FBCon04, I'd recommended separating the pages and actions into separate circuits. Upon further reflection, I'm retracting that recommendation in favor or just separating the pages and actions in your circuit.xml file. One block has all the pages, and another block has all the actions (commented appropriately, of course).

Point #2 is accomplished by the use of a 'service' CFC. It is a singleton CFC that is instantiated into the APPLICATION scope of the app, and it contains all the business operations and data recall for you app. Each business operation has a defined method name and set of parameters. How it's implemented (inlined SQL, a mess of BOs, DAOs, and gateways, magical pixie-powered light-based storage, whatever) is irrelevant, and that's exactly the idea. You should be able to change your presentation layer without changing your service object, and you should be able to reimplement your service object (maintaining the method signatures, of course) without changing your presentation layer.

Point #3 is the standard "use (X)HTML and CSS" line. Make sure you pages are designed from a semantic perspective. Build all the pages before you ever write a single line of CSS. Not going to be pretty, but they do need to be functional in that fashion. Then whip out your CSS magic wand and make it all pretty. This really has nothing to do with FB4.1, but it does have to do with good architecture, because the more divorced your markup is from your presentation (CSS, in this case), the easier it will be to make changes (visual or functional) down the road.

And at last, number 4. Two clauses, and the latter is the more important one. I've seen a lot of people (myself being one) who try to squeeze every last drop of reuse out of a bit of code. Reuse is good, but there are definite times when it's simply a foolish goal to strive for.

In this particular app, most of my display templates (roughly analogous to views in Mach-II) are in their own fuseactions. Again, I opted to not use a separate circuit, but rather name them starting with an underscope (i.e. _entryForm) set them as access="internal", and group them all in their own section in circuit.xml. They include everything needed to render the view, except for designated parameters for reuse (such as the XFA to submit a form to). That means they might include calls to the service object for a recordset, might set their own XFAs, might do basically anything, as long as it's bound directly to rendering that specific view file.

So, in a nutshell, what do I have? A single circuit, broken down into three sections (pages, views or pagelets, and actions). An abstracted service object that encapsulates all the business and persistent operations behind a known interface. Markup that is independant of it's presentation. An app that is both enormously flexible and easy to work with.

Future updates can apply to single sections of the app without affecting other sections if they don't need to, greatly reducing the subsequent testing needed. Poorly implemented sections (of which there are a couple because of time constraints), can be transparently reimplemented without affecting the app.

What I've described isn't quite MVC, at least in the traditional sense. It's subtly different, and while only time will tell, I think those differences result in a much better end result.

Whoops

So it wasn't quite perfect. Realized that I'd botched the new entry config slightly in that comments weren't enabled by default. But that's fixed now, so anyone who happened by in the middle of the night and wondered why the previous post couldn't be commented on, that's the reason. It's fixed now though.

BlueDragon Live!

Well, I'm happy to say that I just deployed my first BlueDragon app to production this evening. It's not much (couple hundred KB), but it's up and running on BD 6.2 Beta. I discovered a whole slew of bugs as I put it together (it was a ~5 day sprint of late nights), but nothing really stood squarely in the way.

The app in question is the backend for this blog (along with The Boisvert Life, for the personal side of me). For various reasons, I'm still using Movable Type as the engine, but I needed an admin interface that I could manipulate, so I rolled my own. Now that it's functional, I can extend it in various ways, which was the whole point of the exercise.

As part of the update, I also installed MySQL 4.1, upgraded the MySQL connector, and a few other things, so I should be golden for a while. This largely meatless post, as you've not doubt guessed, was the maiden post from the new interface, and all seems to have gone well.

Reorganization

I got to thinking last night that I didn't have the categories of the blog broken down very well. The "ColdFusion" category in particular was quite broad. So I broke it down into three categories, and reassigned the existing entries as needed:

  • BlueDragon: entries about New Atlanta's BlueDragon CFML runtime
  • CFML: entries about the CFML language in general
  • Fusebox: entries about the Fusebox framework, and it's supporting topics.

I'm also thinking about making some more feeds of a non-global nature. Not sure if it would be better if they were category-specific, or for groups of categories. Please share your thoughts about what you'd like to see, since, after all, a blog's readership is the only purpose for it's existance, and it should meet their needs.

Will It Never End?

So, BD 6.1 Beta solved most of my problems with CFCs. I'm on cloud nine, and I'm finally getting some work done. It's not perfect, but none of the other bugs were really more than inconveniences (for instance, it gets grumpy when you mix full CFC paths with pathless references to CFCs in the same package). No big deal, just figure out what the issue is, and work around it (always full-path everything, in this case). Plugging away, and I've got the backend of my app finally put together.

Now it's time for the front end. Throw the Fusebox 4.1 skeleton app in there and run it. Error about indexing 'attributes' as an array, trying to set the default fuseaction. Refresh. No issue. WTF? Refresh, fine. Refresh, fine. Touch the code, refresh, error. An hour later I've isolated the problem. Scope leak on a CFLOOP tag iterating over a query.

We all love the fact that CFML lets you reference the fields of the current record of a recordset you're looping over with just the column name. Once you stop the loop, that stops functioning, and you have to again fully scope the field you want (queryname.columnname[row]). BD was doing that, but if you raised an exception inside the loop, it never bothered to turn off that special psuedo-scope. Which meant that for the remainder of your request, variables in the VARIABLES scope that happen to have the same name as a column in the query you were iterating over are shadowed, just as they were inside the CFLOOP.

And of course, 'attributes', that wonderfully versatile, utterly indispensible Fusebox scope is the problem in this case. The loader runs a CFDIRECTORY tag and loops the result, potentially throwing an exception. And guess what, there's a column called "attributes" on queries returned from CFDIRECTORY, so any time it throws that exception, the request fails. (As an aside, the exception in question is an internal exception that the core files use for their internal functioning. It never sees the light of day, except in the CFMX debugging output, if you have the exception list turned on.)

Fortunately, that exception will never be raised in production environments, it's part of a development-mode-only feature (the conditional loader), so no apps are going to break. But it makes development rather difficult, as you might imagine.

Version Control Rules

I was a non-believer in version control for a while. Then about two and a half years ago I took over a decent sized project (around 70,000 LOC) and knew I'd be in trouble without something to help me keep track of it all. So I started using CVS.

Nothing but good things to say. Yeah, CVS has some shortcomings (many of which are addressed in SubVersion), but version control in general is something no one should be without. It does the obvious things, of course, like letting you go back and look at any past version of a file. However, what I find really valuable is some of the codebase management stuff.

For example, say you've got a live version of your site, and you're working on a big update. However, you realize that there's a bug (or the client wants something tweaked) on the current site, and it can't wait until the new version. So you go fix it on the live site. The next step is to replicate the change in the new version. Not a big deal if it's adding an "s" to a word that wasn't pluralized, but if it's a bigger change spanning multiple files, it's a lot harder. However, if you've got your project in version control, it's a snap. You just merge the changes from the live branch to the development branch, and BAM! you're done.

A simpler case. Say you work on your workstation at the office, but you also do some work on the road with a laptop. Every time you switch computers, you need to make sure you have the most recent codebase in the right places. That can mean lots of file copies, and chances are good, some accidental overwrites. If you're using version control, you just check out the code onto both machines, and when you switch, hit "update", and you magically have the most recent version from the repository without any accidental overwrites, and any places where you might have had an overwrite occur is nicely marked for you to deal with.

Anyway, if you're not using some sort of version control, I'd highly recommend starting. I won't lie to you, there is a bit of a learning curve, but six months from now, you'll be thanking yourself for that little bit of pain and suffering, becuase your life will be so much easier.