Wednesday, December 3, 2008

Idea: Give Adobe Bolt Collaboration Features

In my last blog post, I suggested that Adobe include a list of CFML community resources in the upcoming Bolt IDE in order to promote the community to isolated developers who might otherwise be unaware of all the resources out there.

After thinking about it a bit more, it occurred to me that maybe Bolt could take it one step further. Instead of simply using Bolt to point developers to the community, have Bolt bring the community to the developer. Build in an RSS viewer that displays the latest ColdFusion posts from Adobe Feeds. Put in a communicator tool so the developer can converse with other CFML programmers via IM or Twitter. Let the developer screen-share their code with other developers both inside and outside of their organization. Integrate geolocation into Bolt and show the developer a list of other Bolt users (and maybe Adobe user groups) that are nearby. Instead of using e-mail and message boards to communicate with CFML developers, Adobe could broadcast any news announcements to all of the Bolt installs, and Bolt users could submit questions to Adobe and other users via discussion forums displayed in a window of the IDE that gets refreshed automatically.

I'll admit, it's a pretty pie-in-the-sky idea. Given that Adobe only has a finite amount of time and resources, I would certainly not want Adobe to leave out any traditional IDE features, the things that allow developers to code quickly and efficiently, in order to take the time to add all of the things I just suggested.

But if they did have a little extra time, I think adding even one or two simple collaboration/informational features would certainly enhance the product, and perhaps set a trend for other IDEs to follow.

Tuesday, December 2, 2008

Reaching the "Invisible" CFML Programmers

On Monday, Sean Corfield's thoughts on how Adobe MAX 2008 went were published on the Fusion Authority website. One of the events Sean cited in his article was a Birds of a Feather session moderated by Adrian Moreno about bridging the gap between expert/guru CFML developers (the ones most visible in the online CFML community) and "9 to 5" CFML developers.

I don't know the details of what was discussed in that session, but it relates to an issue that crosses my mind every once in a while: how do you reach out to developers when you don't know who or where they are? And, conversely, how do we help these "invisible" developers find (and participate in) the community?

I was a full-time ColdFusion developer for almost two years before I really became aware of the ColdFusion community. My predecessor, to my knowledge, never participated in the CFML community or went to any conferences or user groups, so it never crossed my mind that such resources existed. I don't remember how or when I realized that there was a community of folks with which I could converse about ColdFusion development (though it was probably at CFUnited '05), but the point is is that it wasn't an automatic process.

I think this is an area where Adobe needs to step up and promote the community as part of the overall "ColdFusion package". Every sale of ColdFusion should include a list of CFML community resources and a statement that encourage organizations to share that list with any ColdFusion developers they are aware of. If Adobe is skittish about including links to resources that might disappear over time, at the very least they can include Adobe-sponsored resources like Adobe Feeds or the new Adobe Groups site.

Even that kind of effort might not reach all the CFML developers out there: in some organizations (like mine) where the ColdFusion server is running in a shared environment, the organization that owns the CF license may not know who all is using the CF instance. So here's another idea: put links to community resources into the new Adobe Bolt. If Bolt is meant to be the premier IDE for CFML developers, then there's a good chance that even the "invisible" CFML developers will grab it and gain access to all the resources it provides.

Monday, October 27, 2008

Applications Are Only as Beautiful as the Processes They Replicate

In an ideal application development process, you work with the client to get an accurate picture of all of the business logic involved in the process the application is supposed to handle, and the end result is a robust system built with clean, understandable code.

But it doesn't always work out that way (some would say it never works out that way). Most of us have had to deal with "scope creep." In fact, one could argue that most modern CFML-coding frameworks and patterns came out of the need to deal with "scope creep" and other reasons for changing our applications.

But sometimes the challenge in creating a clean application comes from the nature of the business "logic" itself, the real-world process that your application is supposed to mimic and replace. It occurred to me the other day that that is often the biggest hurdle I have to overcome with the applications that I'm asked to construct.

When I work with my clients to figure out what exactly what tasks the software needs to perform, I often discover that the processes at work are often riddled with exceptions and conditionals. Sometimes my clients are consciously aware of these exceptions, but other times I have to point them out and we have to figure out how they need to be dealt with.

We humans can handle exceptions within our thought processes very easily. Computer logic, on the other hand, doesn't handle exceptions so casually (which is probably why errors can be referred to as "exceptions"). Coding for even a single exception to an otherwise iron-clad rule can make the code involved twice as complex and perhaps a bit less than pristine.

While we do all we can as responsible programmers to deliver a beautifully-coded application, I think that sometimes there's no avoiding the touch of ugliness that comes from trying to represent and replicate an "ugly" human-driven process.

Wednesday, September 3, 2008

CF411 and ColdFusion for Educational Use (Oh, And That New Browser...)

Blogging bullet-point style tonight:

  • Charlie Arehart's new CF411 site has a MASSIVE amount of links to tools and resources for CFML and web development. Stop what you're doing right now, go to the page, and store it somewhere (your bookmarks, Delicious, wherever).

  • The announcement that ColdFusion 8 Enterprise is now available for free for educational use (in other words, for learning purposes) was made on Monday. You can find out more at https://freeriatools.adobe.com/coldfusion/

    While I'm glad the announcement is out, I just wish it had been promoted better. There's still nothing about it up on the Adobe home page or even on Adobe's ColdFusion product page. Why not?

  • Last (and least...), Google surprised everyone this week with their new Chrome web browser. It got so much attention that everyone stopped talking about the iPhone, which is admittedly pretty impressive.

    Like everyone else, I've played with it. Here's my take on it (yep, more bullet-points):

    • It runs pretty well.
    • It does seem to run JavaScript more quickly than other browsers.
    • It has a few nice innovative features.
    • It can be quirky at times and it has some flaws (but it is a beta).
    • It has promise, but it doesn't provide any new functionality that I find particularly useful to me.
    • FireFox will remain my browser at work and at home.

     

Friday, August 29, 2008

Leveraging the Ubiquity FireFox Plugin To Access CFQuickDocs Pages

If you're a FireFox user and you haven't tried out the new Ubiquity plugin created by the folks at Mozilla Labs, you should.

What is Ubiquity? The short answer is it's a command-line interface for retrieving and re-purposing web content. For example, the "wikipedia" command built into the plugin takes the word you type in, retrieves data from the top 5 matches for that word (as you type it, no less) in Wikipedia using an API, and displays that data with clickable links to the Wikipedia pages in the command window:



You can see even more interesting uses for Ubiquity by watching the video clip in the Ubiquity blog post.

One of the things about Ubiquity that hasn't been talked about very much is that you can create your own Ubiquity commands using JavaScript and then share those commands with other Ubiquity users (note to jQuery users: Ubiquity commands can use jQuery functions as well as regular JavaScript functions). To that end, I created a very simple command that lets me call up a particular CFQuickDocs page by typing "cfquickdocs" and the name of the CFML tag or function I want to look up:



As Ubiquity commands go, it's not that impressive, but it does let me pull up a particular entry faster than I used to (which involved going into my bookmarks, clicking on the bookmark, waiting for the page to load, and then entering the tag or function I want to read about). And all it took was one function call with four parameters:

makeSearchCommand({
  name: "cfquickdocs",
  url: "http://www.cfquickdocs.com/?getDoc={QUERY}#{QUERY}",
  icon: "http://www.cfquickdocs.com/favicon.ico",
  description: "Searches the CFQuickDocs for the CFML tag or function you enter."
});

Sharing a Ubiquity command is simply a matter of putting the command in a JavaScript file and then creating an HTML page that calls that file. So if I wanted to host/publish the above Ubiquity command, I could just add it via a <link> tag to an HTML file and host it somewhere, and a Ubiquity user could simply visit that page to install it.

If you don't have Ubiquity installed but want to learn more about developing Ubiquity commands, there is an online tutorial that explains the basics. Once you have the plugin installed, you'll have access to a command editor that lets you try out your commands as you code them, and you can read the code for all of the functions that come built into the plugin.

Saturday, August 23, 2008

If You Build the App, Someone Just Might Use It: You Never Know

I was rather surprised to see my colorPicker AIR application included in a list of 10 AIR apps for web designers on the Six Revisions blog this past week. Then Gary Gilbert gave it more exposure by blogging about the Six Revisions post.

After seeing the Six Revisions post, I decided to check colorPicker's download numbers on RIAForge and got another surprise: the download count was just shy of 800.

As of today, four days after the blog exposure, the download count stands at 1119.

I built the colorPicker mainly for myself (and I still use it). I put it up on RIAForge because I thought a FEW people might prefer something a bit simpler than Kuler (Adobe's color palette tool). But given the number of slick color designer AIR apps that are out now, I would never have expected that many people to have given colorPicker even a glance.

It just goes to show that you never know what apps or code other people might find worthwhile.

Wednesday, July 30, 2008

My first jQuery plugin: textCounting

I've blogged about things I've done with jQuery before, but this is the first jQuery plugin I've developed.

My textCounting plugin lets you show users how much text they've entered into a <textarea> box and/or how much text they can still enter before reaching a set limit. The plugin can be configured to count either the number of words or number of characters entered or still available.

The plugin is designed in a way that a single call of the plugin can affect all of the <textarea>s on the same page if you follow certain element ID naming conventions. There are a number of different configuration options, and it can be used with another jQuery plugin, the Metadata plugin, to retrieve settings and data from a metadata block within the class attribute of the <textarea>s.

To see a demonstration of the plugin in action and to download the plugin, visit:

http://bcswartz.github.io/textCounting-jQuery-plugin/

I want to point out that one thing that the plugin does NOT do is enforce the word/character limit set for each <textarea>: you can apply a CSS class to the HTML element containing the count as a visual notice to the user that they've exceeded the limit, but it doesn't actually prevent them from continuing to type. I was originally going to provide that option, but I realized that a lot of users tend to paste content from another source in <textarea>s, especially when the content is expected to be verbose, and making the user count the words or characters in their text prior to copying it into the <textarea> defeats the purpose of providing the counter in the first place.

If any of you are interesting in writing your own jQuery plugins, I highly recommend you read Mike Alsup's blog post "A Plugin Development Pattern" on the Learning jQuery site. It was an invaluable resource and taught me a lot.

Thursday, July 10, 2008

Google's new virtual room service (Lively) may have potential

Yesterday Google launched a new beta project called Lively. Lively lets you create virtual rooms that people can join and then interact with each other via avatars. The concept is similar to virtual reality systems like The Sims or Second Life, but the difference is that you can put the rooms that you build on your own web page(s).

When I first heard about it, I thought the idea was a bit over-the-top, but I decided to at least try it out last night.

For a first version beta, it's pretty slick. You start off with a basic set of room layouts and room items (furniture, decorations, accessories) to build your room with, but you can choose to add different items from an on-line catalog (currently, all of the items are "free," which seems to imply a virtual currency may be established later when they let folks create their own stuff). Once you add an item to the room, you can move the item by dragging it and then rotate it as needed. You can also add mood music, either from the catalog of music or by uploading your own music file.

Once you've decided an avatar to represent you, you can enter the room and interact with the items (if there's a couch, you can choose to sit down on it). If there are other people/avatars in the room, you can chat with them just like you would in a normal chatroom and your words will appear in a conversation block over your head for everyone to see (or you can whisper privately to a single fellow occupant). Right-clicking on your avatar brings up a menu of gestures and animations you can have your avatar perform, like clapping, laughing, or dancing like John Travolta in "Pulp Fiction" (yes, it's as bizarre-looking as you might think).

I threw together a very simple room and then embedded the code to access the room on a very simple web page on my site. You can check it out if you like, but since you'll need the Windows-only plugin to enter the room, which is the same plugin that lets you create your own room and avatar, you're probably better off trying Lively out by creating your own room.

The need for the plugin to even enter a room is probably one of the biggest drawbacks of the service. The visual evidence strongly suggests that Lively runs off of Flash and was built using Flex (I once saw the standard Flex "Initializing..." dialog box while loading my room) so it's unclear as to why a separate plugin is needed. Maybe Adobe can work with Google to redo the plugin in AIR so it's at least cross-platform.

The other challenge facing adoption of Lively is, well, its usefulness. Right now, it's essentially an enhanced chat room. Some folks have said that businesses could use it to hold virtual meetings, but I don't see that happening unless Lively is upgraded to allow one or more room participants to speak via a microphone and provides a means of working with a presentation (Lively does allow you to display Flash videos within your room but I didn't explore that feature).

And while the idea of having a virtual room up on your home page or blog is kinda neat, it's not going to do you much good unless there's a compelling reason for people to come and hang out in groups in YOUR room. Centralized virtual realities like Second Life are never empty because there's just one world for people to go to: certain areas might be emptier than others, but there's always someone around to interact with. Still, I do see some potential uses for it with established communities. Popular online forums could replace their existing chat rooms with Lively rooms. Businesses could create a guest room or visitor room where website visitors could hang out before interacting with customer service avatars. Conferences like cf.Objective() or CFUnited could have virtual discussions rooms that allow conference-goers to discuss the day's events with non-conference goers ("Folks, the in-person BOFs will be from 8pm to 9pm, followed by the online BOF free-for-all in the Lively room from 9pm to...whenever.")

Heck, the folks on the RIA cruise in February could take the Lively "tropical island" room template and make a place to meet up with non-cruise landlubbers at some point during the cruise if they wanted to.

Who knows if people would make use of these rooms, but the beauty is that it doesn't take long at all to create a basic Lively room, so if it doesn't work out the time lost in trying isn't painful.

It'll be interesting to see if this goes anywhere. My guess is that it'll depend on how much time and effort Google decides to invest in it and whether it will scale effectively (I heard that there were load issues when it first went public yesterday, but I didn't have any real problems with it last evening).

Saturday, June 28, 2008

A list of jQuery plugins I use

As part of his blog post today, Ray Camden and a number of the folks who posted comments pointed out that while it was great that there are a lot of plugins available for jQuery, the downside is that it's hard to know which plugins are any good. I'm not a heavy plugin user, but I'd thought I'd list the few plugins and jQuery UI libraries that I've found to be very useful:

  • jQuery Form Plugin: this plugin appears in every project I've done since I started using jQuery. It makes it dead simple to submit forms via AJAX.

    (Oooh, it looks like the author's added some new features since the last time I download it...I'll have to check that out).

  • Tablesorter: this plugin was actually incorporated into version 1.0 of the jQuery UI library, but I don't see it listed in the current version of the UI library. This plugin lets you sort a table in ascending or descending order based on a selected column.

  • Sortables UI library: this part of the jQuery UI library lets you rearrange items on the page using drag-and-drop (something I've mentioned a number of times here on my blog).

  • TableDnD (Table Drag-and-Drop): the Sortables UI library I just mentioned does not work on table rows (tables are just "different," apparently), but this plugin lets you grab a row and move it up or down within the table.

  • curvyCorners: after trying a few different plugins aimed at letting you create curved corners for certain HTML elements (like <div>s), this plugin, although not perfect, seemed to work best.

    I must say that I couldn't get it to work right in IE, but that might have been because of the way I was using it. And it looks like the author has released a few updates since I last downloaded it, so that may not be an issue anymore.


Anyone else have any jQuery plugins they'd recommended using? Or recommend avoiding? :)

Saturday, June 21, 2008

Some random post CFUnited thoughts

Now that CFUnited's over (at least for me) and I've had some time to rest and mull over things, I wanted to post a few random thoughts and opinions:

  • The entire L'Enfant Plaza Metro station (columns, walls, even some of the Metro railcars that passed through) was one big ad for Adobe LifeCycle. The message: LifeCycle can help the government manage and distribute PDF forms. Unusual? I don't get down into DC too often, but I'd never seen any one company take over an entire station like that before. I want to see more of this high-visibility marketing from Adobe, especially for ColdFusion.

  • Sean Corfield's new asynchronous event-driven framework, Edmund, looks very cool. Being able to fire off events and have them bubble up through the framework much like what you can do in Flex is a very appealing idea.

  • Twitter once again proved to be a useful tool. I found it a lot easy to "tweet" what was going on instead of writing it up on the blog, and thanks to Nafisa Sabu and Elliot Sprehn of TeraTech, anyone who visited the CFUnited website could read the tweets of the conference-goers who had "friended" the CFUnited Twitter account. Hopefully a few folks found my tweets to be useful.

  • While the proposed integration of Hibernate in ColdFusion 9 sounds neat, I think Transfer is still going to be the ORM of choice for many developers, both now and in the future, for some of the reasons Mark listed in his blog and because Transfer works/will work on a larger number of CFML platforms (CF7, CF8, and probably OpenBD and Railo).

  • The discussion about whether or not ColdFusion and ColdFusion development is becoming too Java-like isn't over yet. I met a developer who made the point that it seemed strange (and stupid) to him that we're trying to entice Java developers to use CFML because it makes development faster and easier while we seem to be gravitating towards adding complexity to our development process and our code.

    I made the usual argument that regardless of the focus on OOP in the ColdFusion blogging community, no one was advocating removing those aspects of ColdFusion that make CFML easy to learn and use, and that even OO-style programmers will admit that there are some situations where using an OO application framework is overkill, but he wasn't entirely convinced.

    It made me wonder: if Adobe does develop a teaching curriculum as part of their effort to get ColdFusion adopted in schools, will that curriculum take advantage of CFML's traditional low learning curve, or will they emphasize an OO-style of programming from the get-go?

  • Some promising ideas came out of Brian Meloche's session on promoting ColdFusion/CFML outside of the community. The existence/promise of OpenBD and Railo and Adobe's decision to make ColdFusion free for educational use has opened up a whole new world of possibilities. You should be hearing about these ideas soon, either via the CFConversations podcast or some other channel.

  • Which reminds me, you should check out the CFConversations podcast if you haven't done so already. And I would say that even if I wasn't involved with the project. :)

Friday, June 6, 2008

Going to CFUnited tomorrow

Well, CFUnited begins tomorrow, so I'll be getting up a bit earlier than usual so I can drive to the nearest Metro station and head down into D.C.

The last time I attended CFUnited was back in 2005, so it'll be interesting to see if the conference has changed any in terms of atmosphere and organization since then. Certainly the venue will be different; hopefully that means the wireless network will be more robust/reliable.

And this time I won't be ducking out of lunch to settle on a new house (but hey, I did make it back in time for the next round of sessions).

I probably won't post any new blog entries during the conference (it takes me too darn long to come up with what I really want to say), but I might post a snippet or two about what's going on via Twitter. If you're interested in listening in on those "tweets", you can just follow me on Twitter for the next few days: my Twitter handle is bcswartz.

As for any of my fellow conference-goers (if you're listening), if you don't already use Twitter, you might want to make use of it during the conference. I don't know if Twitter is going to serve as a communications channel for what's going on and where people are meeting up like it did at cf.Objective(), but I imagine if nothing else the CFUnited folks will be making use of the CFUnited Twitter account to send out notices and what not. You can either use Twitter via the Twitter website and refresh the page occasionally, or you can use a Twitter desktop app like Twhirl (built with Adobe AIR).

Of course, that's all moot if we manage to overload the wireless network at the conference. :)

Anyway, looking forward to seeing everyone there!

Monday, May 26, 2008

Using a Transfer decorator to get related records within the same table

 

One of the benefits of using the Transfer ORM in your application is that if you define the relationships between your tables in the Transfer XML configuration file, you can retrieve any objects related to your current object through a variety of functions.

However, sometimes you need to relate records within the same table. For example, in my current project, I have a table of item records which need to be arranged in a hierarchy of unknown depth: one set of items could have two levels of hierarchy, another three levels. Each item, therefore, can have one parent item above it (identified by a parentId field in the record) in the hierarchy and any number of children below it (and all the child records have the current item's ID as their parentId value).

How can you use Transfer to access these in-table relationships? One way is by using a decorator object. As the Transfer documentation explains, a decorator is a CFC file you write yourself that extends the TransferDecorator CFC that comes with Transfer. You associate your decorator with the Transfer object that represents the table in your Transfer configuration file so that when a Transfer object for a record in that table is generated, the functions you define in your decorator become part of that object. So say I define a Transfer object called "Item" in the package "example". Here is the XML in the Transfer configuration file:

The decorator to be called is the itemDecorator.cfc in the "com" directory. I want to have two new functions in the decorator, one that returns a Transfer object for the parent record, and one that returns an array of Transfer objects representing each child record. Here's the code:

In a decorator CFC that extends the TransferDecorator CFC, you can access the current item's Transfer object all of its functions via the getTransferObject() function, and you can access the main Transfer object via the getTransfer() function. So the single statement in the getMyParentItem() function in the decorator CFC is equivalent to:

 
<cfset parentItemObject= transfer.get("example.Item",currentItemObject.getParentId())>

The getMyChildItems() function is slightly more complicated because it needs to retrieve a recordset of child objects first, using the listByProperty() function of the main Transfer object (again, provided via the getTransfer() function within the decorator), then loop through those records, creating a Transfer object for each child record and appending it the array returned by the function.

What if the item record in question is either at the top of the item hierarchy or at the bottom? If there is no parent item, the Transfer object returned by the getMyParentItem() function will have an itemId of 0 (the default value for an empty numeric primary key) and empty values for all of the other properties, so you can test for that condition. If there are no child items, the array returned by the getMyChildItems() function will simply be empty.

This is only the second Transfer decorator I've ever written, so there may be a better way of going about it, but it gets the job done with just two short functions added on to existing object functions provided by Transfer. I like it when things are this easy.

Friday, May 23, 2008

Creating a hyperlink that works with or without AJAX

The current project I'm working on includes a display page where users can see a list of messages generated for them by the system. Each message consists of an <li> element containing the text of the message followed by a hyperlink labeled "Delete". I wanted to make it such that you could delete each message without refreshing the page, but still accommodate users who had JavaScript turned off, and without a lot of extra work. How did I do it? Like so:

...The only other thing you need to do is put a conditional statement in the page/event that is called by the hyperlink that looks for the presence of the additional URL variable ("js" in this case). If JavaScript is turned off, that additional variable will not be defined and the page/event will redirect the action back to the calling page once it's done deleting the message data from the database. If JavaScript is turned on, the page/event will simply delete the message data (no action redirect), and the user simply sees that message item disappear from the list.

Wednesday, May 21, 2008

A ColdFusion IDE feature request: tools for creating Java classes

One of the "themes" that I took away from cf.Objective() was the shortcomings of ColdFusion when it comes to generating a collection of objects. Most everyone agrees on the fact that there is a performance penalty when a CFC is translated into a Java class (or, usually, a series of Java classes) because ColdFusion is a dynamically typed language and Java is not, and reconciling that difference takes processing power.

But not everyone agrees on what the solution to this issue should be. Some folks believe that Adobe should try to improve object generation performance even more, building on the improvements that came with ColdFusion 8. Others feel certain that ColdFusion will always pale in comparison to Java when it comes to object generation and that any enterprise-level ColdFusion application should use pure Java classes on the back end. A few folks at cf.Objective() even advocated integrating ActionScript 3 (the strongly-typed programming language behind Flex) into ColdFusion for use in building objects.

Personally, I would love to see a big improvement in object performance in the next version of ColdFusion 9, but I strongly suspect that equivalent objects written in pure Java classes will still be significantly better in terms of performance despite Adobe's best efforts. If we accept that as the most likely outcome, then the issue becomes how to get ColdFusion developers without any Java background (like myself) to code objects in Java?

I think one way of accomplishing that is for Adobe to create a ColdFusion IDE that provides ColdFusion developers with an easy means to create Java classes and use those Java classes for the model in their applications. It could provide a wizard similar to the CFC wizard tool in CFEclipse that either generates the .java file based on a database table or lets the developer manually define properties and methods for the class. It could also provide a means of generating the Java class files based on an XML configuration file so existing code generators could be modified to work with this IDE feature.

Of course, creating the .java files is only the first step. The IDE should also be able to introspect any .java file and display all of the information a developer would need to interact with that resulting class (properties, methods, data types, etc.) If the developer needs to make changes to the class, they could either edit the .java file directly in a normal IDE editor window (with syntax checking), or via an editing dialog box that lets the developer make changes to the configuration of a method and the statements within the method without having to worry about aspects of the Java syntax involved in describing the method. The IDE would also take care of compiling the .java file to a class every time it is updated and reporting back any compilation errors.

Like I said, I have no Java programming background, so maybe this idea is more than a bit of a stretch. There are also probably other issues that would need to be addressed (like how to manage the dependencies between the Java classes), but I'm betting cleverer folks than I could figure out a way to make it work. Even if the tools for creating Java classes were limited in what they could do, allowing ColdFusion developers to generate their own .java files and Java classes using familiar terms and concepts and then see the results could shorten the Java learning process.

ColdFusion has a long tradition of making it easy for developers to perform certain tasks and operations. When we talk about that tradition, we tend to narrow our focus on the capabilities of the CFML language. We tend to forget that the ColdFusion server software makes our lives easy as well, letting us configure datasources, security features, and gateway processes without having to deal with those issues in our programming code. It's the entire ColdFusion package, as a whole, that makes developing in ColdFusion easier than developing in other languages.

If Adobe develops a ColdFusion IDE, that IDE should also be designed--optimized, in fact--to make developing in ColdFusion easy, regardless of the developer's skill level. So I say if our OO ColdFusion developers need to be able to create their objects in Java, that IDE should help them do that.

Wednesday, May 14, 2008

Table normalization verses long-term data storage

I'm currently working on an application that involves long-term storage of assessment data. Users submit records of their activities and assess their performance, and then reviewers look over those assessments and denote whether they agree or disagree with them. Each assessment database record is related to a reviewer through the unique reviewer id that is part of the assessment record, and I can use that relationship to retrieve the reviewer's name whenever I display the assessment record.

It's a standard example of table normalization. If the reviewer's name was stored within the assessment record itself, and the reviewer changed their name for some reason (marriage, divorce, mid-life crisis, etc.), the application would have to update the name in both the reviewer's record AND the assessment record. But by using the reviewer's id in the assessment record to establish a relationship between the assessment record and the reviewer record, the reviewer's name only needs to be recorded or updated once.

However, this project will entail keeping the assessment data for an undetermined number of years. With the data arrangement I just described, that means I would have to store the assessment records and all of the related reviewer records if I want to be able to keep showing the name of the reviewer when looking at older assessment records. That could result in keeping a lot of extra data about reviewers (addresses, e-mail addresses, logins, passwords, etc.) who are no longer associated with the program simply because we need to keep their name tied to the assessments.

I think this is one of those situations where it makes sense to repeat a little data. Recording the reviewer's name in the assessment records allows me to let the administrative users of the application delete reviewer user accounts without impacting historical data. It means a bit more work in keeping the reviewer's name the same in both records, but in the long run I think it's worth the effort.

Thursday, May 8, 2008

Some updates on reordering items with jQuery

I have a keen interest in being able to reorder items in a list and then record that change in order in a database using JavaScript, specifically with the jQuery UI Sortables component. Here's some things I've learned recently regarding the topic:

Reordering Nested Lists

In my last project, I created a tool that allowed my clients to rearrange nested lists of articles and article categories via drag-and-drop using the jQuery UI Sortables component.

My clients were very excited about the tool when they saw it in the prototype, but they ran into some difficulty when they tried to use it themselves during the final testing. They found it hard to place an item at either end of a list block because there were no visual cues outlining the borders of the list.

It was also nearly impossible for them to move an item around in the top-most list: if they tried to place it in between sibling items or at the end of the list, the item would almost always get dropped at the end of whatever sublist came at the end of the sibling item above.

Finally, the scrollable <div> element containing the nested lists would not scroll to match the drag movement of the cursor, so if they needed to move an item from one end of the nested lists to the other, the item would have to moved in steps.

I solved all of these problems by abandoning the drag-and-drop technique and replacing it with a version of my "click-to-click move" technique. So now when they need to move an item, they click on an icon associated with each item (hidden until needed), and target <div>s are created above and below each item:

They then just click on the target for the place they want the item moved to, and the item is "moved" and the targets are removed (technically, the item is cloned, the clone is put in the new position, and the original item is deleted).

They like the "click-to-click move" version a lot better, so perhaps that's a better means of reordering items when using nested lists. But I recently discovered jTree, a brand-new jQuery plugin someone wrote specifically for sorting nested lists using drag-and-drop. I tried out the demo for it, and it has visual cues to help you position items in the right list, but it does flicker a bit at times. Still, I might play with it the next time I have to deal with nested lists again.

Reordering Table Rows

Lists are nice, but they don't cut it when each item is really a collection of separate items: that's when you need a table. In my current project, I needed a way to reorder the rows in my table as a means of letting the user reorder the data records. The jQuery UI Sortables component, however, does not work on table rows.

I tried to create a pseudo-table by using <div>s within each <li> item to evenly space the data fields in each row. I got it working and looking slightly less than ugly in FireFox, but it didn't fare so well in IE.

I then went browsing through the jQuery UI discussion board on Google Groups and found a post that mentioned a plugin for sorting/rearranging table rows.

It's called TableDnD, and it's a slightly different approach to the challenge. When you click on a row and drag it, there is no drag outline and no gradual movement: if you move up far enough, the content of the row you're dragging and the row above it quickly switch places, and vice-versa if you move downward. It highlights the moving row as you move it so you can keep track of what's happening. The movement is very smooth and you can go as fast as you like.

The only drawbacks I'm aware of so far is that the dragging action will not trigger the scroll bar if you're trying to drag the row beyond the visual limit of the window or scrollable container (much like my original nested list tool), and someone pointed out to me that if you fill all of the cells in a row with other DOM elements such that you cannot click on any of the cells themselves, you won't be able to grab the row and move it. That's not a problem your table cells just contain text, but it's something to keep in mind if you plan on formatting the text with <span> tags or providing input boxes for the user to edtit the cell data.

Tuesday, May 6, 2008

Reflections on cf.Objective()

Like I said in my comment on his blog post, I don't think I can top Ben Nadel's description of the experience of being at cf.Objective().

Still, there are a few things I want to say for myself. First of all, a big thank-you to everyone involved in the planning and execution of the conference. You all did a remarkable job. Same goes for the speakers. I think everyone learned a lot at the conference.

But what really made this conference special to me were the conversations I had outside of the presentations. I've been to CFUnited and even to MAX before, and while I learned a great deal at both, I tended to feel a bit lost, being a solo developer amongst a large crowd of folks who knew each other already or came with colleagues. cf.Objective() was different: it never took more than a minute or two to get involved in a conversation with folks from the blogosphere or even developers I knew nothing about. I always felt like I was part of what was going on. It was truly the most enjoyable conference I've ever attended.

Like I alluded to in my earlier post, I'd been feeling down and negative about, well, a number of things in the weeks leading up to the conference. I feel now like I'm back on track, ready to take what I got from this experience and run with it. So stay tuned.

P.S. A big thanks to Adobe for bring MXNA back to life, better than ever!

Thursday, May 1, 2008

Off To cf.Objective()

...And not a moment too soon! I've been in a bit of a rut lately, so I'm hoping the conference and my fellow conference-goers will help re-energize my enthusiasm a bit. I doubt I'll be blogging much from the conference: I tend to write slowly and with the MXNA blog aggregator still down for the most part, I'm not sure that anyone would "hear" me anyway. So if you want to keep track of what's going on at the conference, tune in to the bloggers covered by one of the other aggregators like FullAsAGoog, Feed-Squirrel, or ColdFusionBloggers

Tuesday, March 11, 2008

Problem: No Drag-and-Drop On The iPhone/iPod Touch. Solution: Click-To-Click Move

As I mentioned in an earlier blog post, the drag-and-drop functions provided by various JavaScript libraries (jQuery, YUI, etc.) won't work in the iPhone/iPod Touch Safari web browser because the dragging gesture is used for scrolling around the web page.

That's a big problem for those of us who use drag-and-drop in our web applications to allow our users to reorder the items in a list, but I've come up with an alternative method for rearranging items using the jQuery JavaScript library that works on the iPhone/iPod browser as well as regular browsers. I call it the "Click-to-Click Move" method (CTCM).

The method involves the user making two clicks (or taps if they're using an iPhone/iPod). The first click is when the user clicks/taps on an HTML element (like an icon or hyperlink) within the item they want to move. That click fires off a jQuery-powered JavaScript function that creates target elements above each item in the list and a target below the last item in the list.

The second click/tap is when the user selects one of those targets as the new location for the item. That click/tap fires another jQuery-powered function that:

  • makes a copy of the item associated with the first click
  • deletes the original item
  • places the copied item beneath the target associated with the second click
  • deletes all the targets

The end result: the item has been repositioned within the DOM structure of the page. You can capture the new item order and save it via a form submit or an AJAX call.

I've put together a "to-do list" application to demonstrate the method. It's designed/optimized for viewing on an iPhone/iPod Touch Safari browser, but you can view it in a regular browser:

https://bcswartz.github.io/jQuery-clickToClickMove-demo/

(Note: Non-iPhone/iPod users can also view it using the iPhone tester site http://www.iphonetester.com, which simulates the iPhone/iPod view minus the touch screen capability).

The demo includes a link to the GitHub repo where the code is hosted.

Finally, here are some screenshots from the "to-do list" demo:

The original list of items:

An item has been clicked, revealing the move, edit, and delete icons for the item:

The move icon has been clicked, and the target elements have been created:

The user clicked on the first target. The item is moved, the targets are deleted, and the list order has been changed:

Monday, March 10, 2008

BlueDragon Goes Open-Source: A Good Thing, But How Good?

Given all the other blog posts I've seen coming through my RSS feeds, this is hardly news at this point, but New Atlanta has decided to open-source their J2EE version of BlueDragon, a web application server package that runs/executes CFML (ColdFusion Markup Language, the language of ColdFusion):

New Atlanta announces free open source BlueDragon edition

I'm certainly happy about this development (as are many ColdFusion developers) because that means that anyone who wants to develop with ColdFusion will now have access to a robust CFML application server without having to spend money for the server software: money is no longer an excuse for avoiding ColdFusion.

But whether or not this announcement will have a significant impact on the prevalence of CFML as a development language in the marketplace remains to be seen. If New Atlanta makes an effort to market BlueDragon to web hosting companies who currently don't offer any ColdFusion development packages, we might see an increase in ColdFusion adoption simply because it's available as an option for developers whose clients rely on 3rd-party web hosting. They will also have to increase awareness of BlueDragon amongst the non-ColdFusion developer community and make it clear to those developers that BlueDragon is a serious, enterprise-class alternative to Adobe's ColdFusion server.

If New Atlanta does all that, perhaps we'll see that surge in ColdFusion adoption we thought would come when price was no longer an issue. But what if that surge never comes? What if price wasn't the big issue after all?

Then what?

Wednesday, March 5, 2008

Internet Explorer 8's Webslices Feature: Widgetizing Pieces of Web Pages?

The first public beta of Internet Explorer 8 was released today. In addition to supposedly being fully web standards-compliant, IE 8 comes with two new...well, capabilites: Activities and Webslices.

Curious (and admittedly a bit bored with what I was currently doing), I did a Google search and came up with a page that does a pretty good job of explaining Activities and Webslices:

IE8 Beta Is Out And With It Some Slices & Activities

The Activities capability allows web developers to provide XML code that will add contextual menu options to certain page content when you right-click on that content, allowing you to send that content to another web page or service, like sending an address on the page to a mapping service like Google Maps.

The Webslices capability is even more interesting (if I understand it correctly): using CSS, web developers can tag a piece of the web page as being a slice. End-users can then save this slice in IE, and IE will periodically check that slice for any changes. If the content is changed, the end-user is notified and they can pull up just that part of that web page as a pop-up widget in the browser.

I don't quite know what to make of it...it's like they've made it possible to send a request to a webservice from the page (Activities) and to make part of the page a webservice (Webslices).

It's an interesting idea, but what will the other browsers do with this stuff?

Wednesday, February 27, 2008

ColdFusion 8's Image Functions + jQuery= A UI For Adding Text and Color Blocks Into An Image file

One of the new features in ColdFusion 8 is the ability to manipulate images using ColdFusion tags and functions. For example, the code below (all server-side code) will take an image file on the server, overlay it with text, and create a brand new image file in temp space and display it to the browser:

<!---Assign the image file to the carImage variable--->
<cfimage name = "carImage" action="read" source="ferrari.gif"/>
<!---Add the text "Fast car!" to the image and place it 10 pixels from the left and 15 from the top--->
<cfset ImageDrawText(carImage, "Fast car!, 10, 15)>
<!---Display the new image--->
<cfimage source="#carImage#" action="writeToBrowser">

A week ago, an idea popped into my head: "What if you could create a UI tool that would let a user decide what text should appear on the image and where it should appear?"

I decided to try and answer that question. The result: a working proof-of-concept that lets you add text and blocks of color anywhere on a selected image using a UI tool powered by jQuery JavaScript functions. When you're done manipulating the image, you submit the data defining your changes to ColdFusion via an AJAX call, and ColdFusion creates a new image in temp space based on that data and displays it. You can save the new image down to your computer or store the data you submitted in the database so the image you made can be reproduced without permanently storing a new image file.

The fact that it only took me a week to do this (no more than 25 hours) is a testament to both the power and simplicity of ColdFusion and jQuery.

The GitHub repository containing the code can be found at https://github.com/bcswartz/imageCaptionator-ColdFusion

You can watch a YouTube video of the application in action at https://youtu.be/JcLnO6zB3MM

Thursday, February 21, 2008

Changing Individual CSS Styles with jQuery

Back when I was writing my own custom JavaScript functions, I learned that there wasn't a single, simple way to change the individual style settings (like "font-weight:bold") for an HTML element that worked on every browser. My solution was to change the CSS classes assigned to the element instead: I wrote a library function that would allow me to add, remove, or replace any class assigned to an HTML element and simply created as many class definitions as I needed in order to accommodate the style changes. It was actually a pretty effective workaround because it let me effectively change multiple styles with one function call.

When I started using jQuery, I quickly learned about the "addClass" and "removeClass" core functions, which I could use instead of my library function:

$("#missionStatement").addClass("importantTextClass");
$("#userProfile").removeClass("hideTextClass"); 

...So I continued with my routine of changing styles by changing classes, even though sometimes I only needed to change or remove a single style setting. No harm, no foul.

But changing classes wouldn't work for the wacky little project I've been working on recently: I needed to be able to change several styles for an HTML element individually, and writing a class to handle every permutation of the possible style combinations was impractical.

So I went to the jQuery web site, hopeful that the brilliant folks at jQuery had something that could help me out.

And they did: the "css" core function allows you to read or set any individual style or styles:

if ($("#missionStatement").css("font-weight")== "400" || $("#missionStatement").css("font-weight")== "normal")
 {
   $("#userProfile").css("display","none");    
   $("#missionStatement").css({ fontSize:"24px", fontWeight:"bold" });
  } 

Have I mentioned that I love jQuery? :)

Tuesday, February 19, 2008

Thoughts on Future Trends in Computing

At our staff meeting today, my manager told us our director was looking for input on emerging "21st century" technologies and technology trends, and to send him our thoughts so he could pass them along. Here's what I sent:

  • The introduction of applications that have both a web and and desktop front-end to access server-side data, with the desktop application provide offline functionality and data storage that can then be synchronized with the back-end data. Examples of this upcoming movement are Adobe AIR, Google Gears, and the Mozilla Prism project.
  • Increased portability of programming languages to other platforms. It's now possible to code .NET or Java application in dynamic languages such as Python or Ruby.
  • Increasing development of RIAs (Rich Internet Applications) based on AJAX, Adobe Flex, Microsoft Silverlight, and JavaFX. RIAs allow for more engaging and more powerful user interfaces and (in the case of the latter 3 technologies) make it easier to integrate audio-visual material into applications.
  • The continued growth of "cloud computing," where organizations store their non-critical data on external servers maintained by a third party but controlled and accessed by the organization over the Internet. The chief example of this is Amazon's S3 data service.
  • The continued trend of exposing the social (people-based) connections between data started by the social networking sites. The social networks themselves may stop growing, but the idea of using a person as a focal point for otherwise unrelated data is going to stick around.

...Hardly earth-shattering predictions, but other than within my particular unit, my organization isn't that hip to web trends.

Sunday, February 17, 2008

Some Design Considerations When Building A Web App for iPhone/iPod Use

I recently finished a small project that involved optimizing some simple web applications for use on an iPhone/iPod Touch. I won't bore you with the specifics of the project (unless someone asks) but here are some things I learned during the experience:

  • There is no touch analog for click-and-drag (probably because dragging is an action reserved for moving around the page), so drag-and-drops will not work and you cannot select text for copying, cutting or pasting. This means the dragging tools/effects implemented in the various JavaScript libraries (jQuery, Yahoo YUI, etc.) won't work.
  • There's really no way to "hover" over an element with your finger, so any CSS style initiated by hovering will not come into play.
  • Because fingers are less precise than a mouse cursor, you have to make sure there is enough space between different clickable elements (links, checkboxes, etc.) so that the user can easily click only on what they want to click on. So if you have a vertical list of hyperlinks, you may want to put at least one line of space between them.
  • When you click on a text field, textarea, or select box, the page zooms in and either a keyboard or a list of drop-down choices appears at the bottom of the screen. Once you make your choice/enter your text and tap the "Done" button, the zoom doesn't reverse, so you end up still focused on the input element. That means if you have a submit button off to the left or right, you have to tap and scroll the page to it in order to tap it. If your application is designed to be viewable in the iPhone/iPod without the need for zooming, you might be able to negate this effect by disallowing all zooming (haven't tried this yet).
  • Selecting a choice from a drop-down box does not fire off the onChange JavaScript event for that box, probably because the action is intercepted in order to allow the iPhone/iPod to do the actions described in the previous bullet. The onChange event for text boxes might be similarly affected.

Tuesday, February 12, 2008

Data Storage Forecast: Only Partly Cloudy

Over the past few weeks, the idea of moving data off of desktops and locally-controlled database servers and "into the cloud" (onto shared data hosting services like Amazon's S3) has been gaining more attention. A guy named Nicholas Carr went so far as to predict the demise of the IT department as businesses essentially outsource their data processing/data retention (NetworkWorld, 1/7/08).

There's no doubt that individuals store more data online these days than they used to because of the rise of applications like Facebook, Flickr, and Google Calendar. Any data that has a social aspect to it gains value by being "out there" for others to view and interact with.

There are also business processes that involve collaboration with other business partners, where arrangements are made to exchange information or tangible goods via a buyer/seller dynamic. Again, it makes sense that the data and even the applications that power such collaborations could be managed and hosted by a third party.

But there will always be a desire to keep certain data close to the vest, even if that means maintaining an internal hardware and network infrastructure. Colleges and universities are not going to outsource their student data to a third party, and medical institutions are obligated by law to safeguard medical information. Banks will probably take a pass on shared data hosting as well. Even if cloud computing becomes more accepted and reliable, there will always be groups and individuals unwilling to give up that control despite any cost savings.

Thursday, February 7, 2008

Switching Between Sets of Database Tables On The Fly

Ever need to tell your ColdFusion app to run select queries against a different set of tables while you do something to the original set (like perform a batch update)?

I did. Here's how I did it.

First, I gave each table in each set a two-part name, two words separated by an underscore. The first part of the name was descriptive of the data in the table ("chapters","sections", etc.) while the second part of the name identified the data set the table belonged to ("live", "archive", whatever). So the "chapters_live" and the "chapters_archive" tables were exactly the same in structure.

Then I created an application variable called "application.tableSuffix" and set its initial value to "live".

(Can you see where this is leading?)

Finally, I changed my select queries to use table names comprised of the first, data-descriptive part of the table name, the underscore, and the value of application.tableSuffix:

<cfquery name="showChapters" datasource="ds">
   select chapterTitle, chapterIntro
   from chapters_#application.tableSuffix#
   order by chapterOrder ASC
</cfquery>

Once that was done, I could change the table set my select queries ran against at any time by simply changing the value of application.tableSuffix. Two things worth noting:

  • This technique only makes sense if only one set of tables can be updated by the user: if users can make changes to either set, you'll have to figure out how to resolve the differences between the data in each set.
  • If the switch could potentially be in place for awhile, you might want to store the current tableSuffix value in a database record or a file and then retrieve that data in the onApplicationStart method of your Application.cfc file so that the current value is preserved even if the application scope expires.

Tuesday, January 22, 2008

Techniques for Providing Instructions Within a Web Application

Some of the processes you find in web applications are fairly standard. Most folks can fill out a contact form, or fill out a survey, or make a calendar entry without the need for too much explanation. But what do you do when the form involves business rules that the user may or may not know, or presents the user with a number of options?

I always try to make sure the tools and the pages I put in my web applications are fairly self-explanatory, especially those tools and pages that only the administrative users of the application interact with.

The folks who end up using and administering my applications (my clients) are almost never technical people, so I start off each administrative page with a brief explanation of what the page does and how you save any information entered on the page. Once they've used the page, they can always skip over the intro and go right into the form or tool.

If the overall form requires a bit of explanation, something that can fit into a few short sentences, I'll put that explanation right after the basic description. If certain form fields require special instructions (like the requirements for choosing a sufficiently-strong password), I'll put the instructions right next to or under the input field, so that they focus on the instructions right when they need them.

Sometimes, though, there's too much to explain and still fit on the page without using up a lot of screen real-estate. In those cases, I'll present the explanation via a JavaScript pop-up window that comes up when the user clicks on a help symbol like a question mark icon.

I try not to use too many of the help icons on a single page, but it's a great way to present additional information to only those folks that need help, without getting in the way of experienced users.

Up until now, those techniques were sufficient to provide my clients with the guidance they needed to use their new application. But my latest project has taken help documentation one step further.

This project allows my clients to create news articles for the web using a JavaScript WYSIWYG editor, so in the prototype I added a few help icons to the editing page in order to explain how to use the editor, how to upload images files, etc. When I showed my clients the editing page and the help icons, I told them I would give them the ability to edit the help text that was displayed in the pop-up windows (so they could phrase the help in a way that made the most sense to them).

They liked that idea, but they had an even better one: they wanted to write their own in-application user manual, so that the primary users of the application could write procedural instructions (instructions not necessarily pertaining to the use of the application) that would guide other users in the office whenever they needed to fill in for the primary users.

So I built a tool to let them write chapters for their manual: they have a simple text field for entering a chapter title and a WYSIWYG editor box for entering the chapter content. They can also rearrange the order of the chapters on the master page using a variation of my jQuery-powered list rearrangement tool (see related entry). The header of the application hosts the "uber" help icon they click to bring up their manual in a large pop-up window, where the chapters are listed as hyperlinks that load the corresponding chapter content into the right-hand content area via an AJAX call.

Only time will tell if they actually write their own manual, but if they do, I may include a manual-writing tool in future applications. If your clients are willing to write some of the documentation for an application, it's a good way to get them further invested in the project, and it can end up saving you some work in the process.