String Concatenation Tricks

Massive string concatenation isn't used all that often in CF, but it's sometimes needed. My most common use is probably creating text-only emails. You can do it with the output stream directly, but you usually run into problems with an extra line break here or there, because of the way your CF tags are laid out. But if you try and correct the formatting in the output, you end up with CF code that is horribly jumbled. The solution is doing string concatenation within a variable, but it has some downsides as well: it can be cumbersome, can be hard to follow, and for large strings can be relatively slow (because of the way Java optimizes strings).

Java, however, provides some classes that can make this process a lot easier. The simplest one is java.lang.StringBuffer. Here's an example:

<cfscript>
sb = createObject("java", "java.lang.StringBuffer").init();
sb.append("my text" & chr(10));
sb.append("my other text" & chr(10));
if (1 EQ 2)
  sb.append("never happen" & chr(10));
myTextString = sb.toString();
</cfscript>

As you can see, there's not "myTextString = myTextString & " repeated all over the place, which makes the code easier to follow. However, you still have to deal with the carriage returns, but we can solve that problem too. Now we're going to use two classes from the java.io package: StringWriter and PrintWriter. Here's the example:

<cfscript>
sw = createObject("java", "java.io.StringWriter").init();
out = createObject("java", "java.io.PrintWriter").init(sw);
out.println("my text");
out.println("my other text");
if (1 EQ 2)
  out.println("never happen");
myTextString = sw.toString();
</cfscript>

We're using the println method, which prints the supplied text, along with a newline (and/or carriage return) character. You can also use the print method to print some text without adding a newline.

In both cases, mixing logic into the string generation code is simplified, because whitespace in the program code itself is irrelevant, just like normal concatenation, but we're stripping out some of the nastiness that concatenation brings. In the latter example, we take it a step further by using some of Java's built-in classes to help take care of the nasty work (dealing with newlines).

Just as an aside, this is a prime example of both the Adapter and Decorator design patterns. The StringWriter adapts a StringBuffer for writing to, rather than string manipulations. Note that you don't see the StringBuffer in the second example, it's internal to the StringWriter instance. Then the PrintWriter decorates the StringWriter to supply additional methods to make using it easier (namely print and println).

BlueDragon 6.2 Beta

I downloaded and installed BlueDragon 6.2 Beta this evening, and as if by magic, the error messages disappeared, and for the first time in quite a while, I actually got a request to run from top to bottom without an error message!! Needless to say, I was pleasantly surprised.

At the very least, I should once again be able to continue working on my various projects, and heck, if 6.2 goes gold soon enough (and I don't run into any more seemingly random glitches), I might even get to avoid buying CFMX. That being said, I'm still going to continue scraping together cash for a license.

More BD Fun

I'm mentioned a couple times before that I'm working on an abstract persistance framework loosely modeled after CMP entity beans (of EJB fame). Understandably, this requires some fairly complicated CFC work, including dynamically generating new CFC files and such.

However, BD seems totally unable to handle anything but the simplest of CFC usage, and I'm constantly plagued by random errors, particularly with locating CFC files. I'm quite tired of this, and while New Atlanta has been very understanding with trying to get bugs ironed out (much moreso that Macromedia, though they've also got a lot more bugs to squash), I'm sick of spending my time helping a company improve it's commercial offerings for free.

So, I'm beginning a crusade to eliminate my BlueDragon dependance once and for all. If anyone has any consulting work they need done, please let me know. Doesn't have to be much, just as long as it pays. Total cost of CF (with subscription) is $1976.28 including tax and shipping. I should be getting a check for the first couple hundred in the mail tomorrow, so I'm on my way. Just need to keep it coming.

CFQUERYPARAM, Part Deux

Cfcoder made a good point about why some people (particularly novices) probably don't use CFQUERYPARAM, and that is that if you use CFQUERYPARAM, you can't use the CACHEDWITHIN or CACHEDAFTER attributes of the CFQUERY tag.

That being said, I don't think this is necessarily a valid point. In general, optimization should be the last thing on your mind when you're coding. If you need to cache something as granular as a query, you shouldn't even consider the need until the application has been written, and it's been demonstrated that caching that query will remove a performance bottleneck that actually affects the application.

By and large, novice programmers are not going to be working on applications of sufficient size that such performance tweaks will be necessary. If they are, and it truly is a novice programmer, chances are good that the real problem lies in the application's design at a much higher level. If that's not the case, it is amazingly trivial to cache information (including, but not limited to, queries) in any of the shared scopes that CF exposes. Any novice that assumes skipping CFQUERYPARAM for reasons of caching is merely confirming their inexperience. I'll freely admit to arriving at that conclusion at one point in my career, but not any more.

A much better route is to place the query into a reusable module, be it a UDF, an include, a CFC method, or even a custom tag. Within that module, you can set up and use a custom caching mechanism, which could range from a simple shared-scope variable, to utilizing a shared-scope CFC instance that manages a cache, to an advanced caching framework. If your query is already in a CFC method or an include (such as a Fusebox fuse), then you're 90% of the way there.

CFQUERYPARAM, People

I'm amazed at the number of problems that crop up on the mailing lists that can be solved simply by using CFQUERYPARAM rather than inlining values directly. I'm also amazed at the amount of code copy and pasted into emails regarding unrelated problems that don't use CFQUERYPARAM.

CFQUERYPARAM is your friend. Use it. Always. If you're a lazy bastard like me, set up keyboard shortcuts. I have three, one for integer, one for varchar and one for timestamp, and they all leave my cursor in position for entering the value.

And yes, I do email code without CFQUERYPARAM included. That code is always code I've typed on the fly for the email, and I almost always make a note immediately aftewards that I didn't use CFQUERYPARAM but you should. Code I email is always for illustrative purposes. If it's "real" code, it'll be a .CFM in an archive attached to the message.

The Ant Goes Marching…

Ant, for those of you who don't know, is a Java-based build system that was designed to replace 'make' for Java projects. I've been using it a lot recently to automate various repetitive tasks that I have to do. Ironically, I've yet to build any software with it.

The two most recent things I've used it for are for automatically publishing web sites from CVS and for managing my DNS server. In the former case, ant takes care of the check out, assembling the needed modules, switching to production mode (in fusebox.xml), and publishing to the web server, all from a single command. The latter involves not only generating all my zone files from templates, but also parameterizing various bits of info (like the SOA values) based on external property files. If I ever need to change a given timeout, I just update the property file, regenerate, and all my zones are instantly switched.

It's a really useful tool, and well worth the bit of time to figure out how to write the build files.

Loosely Typed Languages

On CF-Talk today, someone asked about these two expressions:

<cfset i = 5 />
<cfoutput>
#i GT 0 AND i LT 4#
#i GT 0 LT 4#
</cfoutput>

Obviously the first one will be false (5 is not less than 4), but the second one is true! Why, you ask? Because CF is loosely typed, which means that a given value isn't necessarily a single type (number, boolean, string, date); it can seamlessly move between types as needed.

For instance:

<cfset x = 4 + "5″ />

That's going to result in '9', even though you're adding a number and a string. Back to the original example, what's happening is that the first operation (i GT 0) is evaluated to 'true'. Now it looks like this: true LT 4. 'true' is then coerced into a numeric value (because a number is needed to compare with another number), resulting in this expression: 1 LT 4. That expression obviously evaluates to true.

What's all this mean? You have to be extra careful when using a loosely typed language or you can run into really obscure problems like this, that are very hard to find and fix. Strongly typed languages (where implicit type conversions aren't alloed) won't allow things like this to happen. In this case, the language would have complained that you're comparing a boolean to a number, and aborted with an error message.

Counter Computer

I finally got my counter computer fully functional. The monitor still isn't hung, but it's all working now. The last step was to get a wireless card for it so I didn't have to run an Ethernet cable over from where our router is. For some stupid reason, it was cheaper to buy a full-on wireless router with built in 4-port Ethernet switch rather than a PCI wireless adapter. No one understands why. But it works just as well, and gives me the advantage of having a better signal on my Powerbook at the other end of the house.

I took a couple pictures: one with the cupboard closed and one with the cupboard open. It'll look a lot cleaner once I get the monitor hung and have hidden the wires, but at least it's working now.

I'm Popular?

I just noticed an interesting thing. My blog is getting more traffic in than The Boisvert Life for the first time ever. I guess this means that I'll actually have to start providing real content. ; )

JSP?!?

I've had a few questions recently about my choice of JSPs for my personal web site. Obviously I'm a ColdFusion guy, so it seems like I ought to be running ColdFusion for my personal site. I'm also an avid Fusebox user/developer, so it makes sense that I'd be using Fusebox as well. Instead, I seem to be running JSP, without Fusebox, or even a Fusebox-like framework.

If you're interested in the nuts and bolts, I drew up an architecture document about how the site works. However, it doesn't really address the reasons for my choices. The biggest driving force is cost. ColdFusion costs about $1300 for the basic edition, which is way beyond what I can afford for a machine that will never make me money. BlueDragon (from NewAtlanta) is a CFML runtime that is available for free, but if you've read my recent posts, it's pretty clear that I don't think too highly of it.

That left other free technologies. PHP is one, but I've never really liked it. It was a little too much like Perl and/or C for my tastes. .NET was right out, since it's Microsoft, and MS software has no place on a server that doesn't have a sysadmin available full time. That left a few minor players, and the 800 lbs. gorilla of J2EE, specifically JSP/Servlets, which is the route I went.

I wouldn't call myself a Java programmer, but after ColdFusion, that's definitely the language I'm most familiar with. JSPs are a logical extension, bridging the gap between "real" Java and CF's tag-based goodness. I built myself a bunch of functions and tags that exposed a very helpful subset of CF's native functionality to JSPs, and from there built the site.

I've since installed BlueDragon on the machine (for my Fusebox work), and am planning on moving over to 100% CFML again at some point. However, what I've got right now works well, and it's easy for my wife to manage The Boisvert Life via MovableType's admin interface.

I'm currently building out a CFC-based model framework loosely based on EJB's entity beans. When that's ready, the proof-of-concept application will be a CFML blog, which will replace this one. No idea when that'll be ready, but it's going to kick ass. To the tune of "Barney will never write a SQL statement again". Yes, you read that right. No more SQL anywhere; the framework will write it all for you, based on an XML descriptor. And not dynamically either, so it'll hella be fast, even without agressive caching.

When available, it will be released under an open source license, of course, probably MIT-ish.