Timeline Widget on C-Span

If you haven't seen it, C-Span has a "Debate Hub" web site. Now whether you're interested in the presidential debates or not, if you're interested in good software their site is interesting. Or at least the debate timeline widget is interesting. The image below is linked to a larger version.

[More]

Where Has All the Help Gone?!

Years ago it was considered if not horribly important at least a popular notion that software should include "help" documentation that was ... well... helpful...

What happened to this notion? Why is it no longer possible to get helpful help from the help feature in an application?

It used to be that in Microsoft's Enterprise manager I could open help, search for a keyword and if I didn't find it immediately at least I was directed to a copy of the Books Online (BOL) that had been installed on my machine with the client tools. And don't get me wrong, I'm all for "livedocs" and central wikis, they're awesome for centralizing knowledge for a given technology. The ColdBox wiki is pretty thorough, as is the Transfer wiki -- the community is doing a good job of banding together and making information generally available.

No, I'm talking about the efforts of companies like Microsoft in particular (I'm sure I've seen others), where attempts to centralize documentation end up just making things worse than they were before. Take for example, the management tools for SQL Server I mentioned before. I used to be able to hit the "help" menu and get help. NOT ANYMORE! Microsoft has decided to step up into a bold new horizon of tomorrow's software, where requesting help from within an application sends you to a central repository of information for EVERYTHING!

So I hit the "help" menu and first I'm accosted with a dialog box with a series of 3 radio buttons to choose from, only... wait... TWO of the THREE options available to me have been DISABLED! So I'm being asked to make a selection - I can go to their central repository or I can go to their central repository! Wow! So many options! I think I'll go to their central repository. There I'm given a set of frames that do vaguely resemble the old-style help application, just minus the help. In the upper left corner where I'm hoping to see a "search" option or some way to enter a phrase or keywords I see "Filtered by" with a drop-down. I open the drop down and notice ther'es only 1 option labeled "unfiltered". Wow! I can choose between unfiltered help and unfiltered help! So many options! I think I'll get unfiltered help. Below this is a tree of items regarding "help on help (Microsoft Document Explorer Help)" ... umm... What happened to help applications being intuitive? Why do I need help to use the help application?

So finding no help there I move on to the panel on the right where I find they've opened a browser window for me... There's a URL at the top showing me that I'm on an ASPX page. At the top of this page it says "How DO I (SQL Server)". Okay that's good. I appear to be at least in an area related to what I want to know. In this section "SQL Server Database Services (How Do I)", "SQL Server Analysis Services (How Do I)", etc. you get the idea. None of them really what I want to know, which is how to open an/the object explorer.

Oh hey! There at the top! It says "Ask a Question". Have I suddenly found the mythical search feature?! Nope... Takes me to MSDN Search where if I type in "open the object explorer" or even "object explorer" (WITH QUOTES) I get the first 1-10 of over FOUR THOUSAND results, almost none of them having anything to do with SQL Server. So I go back (which in itself is a challenge), and finally as I'm writing this article I see "Search" at the top. Which even once I've found it, still doesn't seem to produce any results that explain how to open the object explorer...

::SIGH::

DeviantArt

I've had a profile on Deviant Art for a little while now at http://smolderingremains.deviantart.com. A while back they added a feature on their site that allows you to separate your gallery into categories or sections, which I thought was a nice addition because not all my art is in the same genre. Right now I've got a lot of comic strips or cartoons that I'm using to promote WooHooLigAN.com and those are considerably different in style than my older black and white inkings. It makes sense to me that someone viewing my gallery might like to see a section where they can view all my inkings together and by themselves rather than being forced to comb through my entire gallery. Or for that matter that someone looking at my gallery at first glance wouldn't even think that I did that kind of work, so the section allows them to see my "range".

What doesn't make sense is the interface for managing those sections.

The Deviant Art interface for managing the gallery is the kind of interface that really makes me think "why do we (programmers) do this to people?"

First of all, they've become really fond of drag & drop -- they use it all over the place. You drag thumbnails to change the order of the images in your "featured" section (everyone has a "featured" section), you drag pictures to add them to your favorites, etc, etc. But even though your own custom sections are sitting right there in the sidebar in your gallery page, you CAN'T drag thumbnails onto them from your featured section -- or from any section. Don't get me wrong, I actually like their drag & drop (even though I've stopped using Firefox to view the site because it crashes, so I end up using Internet Explorer because the site is more stable there). So I'm actually happy with some of their interface changes, I just wish they'd gone all the way with their D&D implementation.

To categorize your images you have to log in, go your gallery and press an "edit" button at the top, which places you in an edit "mode" (ahh modality... the good old days). Once you're in the edit mode, you still CAN'T drag images onto your sections. Instead it replaces the name of the image below the thumbnail with a small blue button graphic with a down-arrow on it. Clicking the down arrow produces a list of your sections (which are already sitting in the sidebar in front of you off to the left). Okay, great... in the list it says either "put in xxx section" or "remove from xxx section" -- indicating both whether or not it's in that section already and letting you perform the task of categorizing... at least, that's how it works in the "featured" section.

Once you've removed an item from the "featured" section then once you go into the section where you placed it before (I placed one in "cartoons"), the list changes -- it removes every item in the list except for "remove from xxx section" (the current section)... Presumably, the system still knows what your sections are -- they're still sitting right in front of you off to the left. But you can't add anything to them -- or add anything back to your "featured" section, even though everyone has that section. The only thing you can do is "remove"... And I thought to myself "well I wonder if I remove it from this section, if the system will automatically add it back to "featured" since it won't be in any of the other sections anymore?" Nope. If you remove it then it just doesn't show up in any of your sections...

So I contacted their tech support because I thought I'd "orphaned" one of my illustrations and I get a response back to inform me that once an item has been removed from the "featured" section, you have to find it in "browse". Uhuh... the "Browse" area essentially is the original gallery -- it shows all your work sorted by popularity or submission date (so in other words you can't order them here). And in "browse", suddenly, like magic, that pull-down menu below each of the thumbnails shows all the "put in xxx section" options again. You know, the ones that disappear when you enter a category. ... sigh ...

Catch-22

On the whole, most software BLOWS. There are of course exceptions. I tend to think that the ColdFusion server is one of them. My favorite example however is email. I've been using the internet for about 14 years now, and programming professionally with ColdFusion for nearly a decade. And in all this time, I have yet to find an email client that even comes close to approaching a vague semblance of what I would call "good". Yes, they all "work", but I'm not talking about software that works. I'm talking about "good" software. I'm pretty certain that Pine works. I'm also pretty certain that it SUCKS in the sort of way that likely only someone subjected to water torture can truly appreciate. In all the time that I've used email, to this day, I can only find one that's "the lesser of evils".

Like water torture, bad software doesn't leave any marks on its victims, but the effects are dramatic and far-reaching. Just ask the families of those who died in a plane crash mentioned in Alan Cooper's Inmates as a result of software with no safeguards to warn the pilot that he was about to "land" the plane rather abruptly into the side of a cliff face.

Part of the reason this happens is that most commercial software is developed by people who are both significantly removed from the impact of their work and who are largely motivated by a paycheck. It's similar to the decision of the Ford Motor Company to avoid a recall to make an $11 repair to all of their Pinto line (the barbecue that seats four), resulting in a large number of injuries and deaths from a product they knew was defective. That decision was made initially by an individual who was far removed from its impact and of whom the company requested only a costs benefits analysis. When viewed in purely capitalistic terms, it was going to cost the company less money to pay the legal fees (according to the analysis) than to perform the recall. Each person involved "knew their place" in the corporate hierarchy and understood their job in very specific terms - "I'm being paid to analyze the finances - it's not my fault if the people paying me misuse that information".

As an industry we have a moral obligation to connect the dots between our engineering and the human impact much later down the line. We frequently fail that moral obligation because we view the work as "just a job" and for that matter that often our employers expect and even demand that we view it as "just a job". They ask us to "just get the job done", without really questioning its impact.

There are a small number of people trying to produce some alternative. Some semblance of software created with a "moral center". Software made by people who genuinely care about the outcome. These individuals can be found mostly although not entirely in the open-source community. The open source community could be AWESOME... if it weren't for all that damned free software.

Therein lies the catch.

Commercial software tends to suck because most of the people paid to create it are "just doing their job". Hence they create software that's "good enough for government work", because at the end of the day, all they really wanted was for the day to be over in the first place. Necessity is the mother of frustration.

Open source software tends to suck because the people not paid to create it need to eat. Necessity is the mother of frustration.

Damned if... Damned if...

What we need is a revolution.

Make It Snappy!

So there's been this thread on the cf-talk mailing list in the past couple days about performance. Of course as a developer, I generally end up performance tuning just about everything at some point or another... although I hate doing it. I realize that performance tuning is necessary, but I hate doing it because that means instead of creating an interface to accomplish a new goal for my customer, I'm just making it possible for them to accomplish a previous goal very marginally faster.

The analysis usually goes something like this:

  • I would really like for users to be able to send email to x group of customers at once. There is currently no way for them to achieve this goal using the existing system, except to manually comb through the list of users in that group and copy their email address into a text file or enter them into their email client. Doing this in some cases would require an hour or more of tedious leg-work for the customer. A tool to do this would allow them to achieve this goal in mere minutes or even seconds.
  • Users are upset (and raising hell) about the fact that it takes 12 seconds to load their list of most-used and most-recent contacts. Improving performance here would reduce the wait from 12 seconds to about 4-6 seconds, imo a marginal improvement.
  • I have 5 hours of development time. So instead of creating the tool that lets them do in a few seconds what currently may take over an hour, I'll spend the next 5 hours tediously shaving off mere milliseconds from the process they're complaining about.

For some reason that I don't think anyone really understands, humans (customers) seem to be totally unable to put the previous example scenario into proper perspective. Now I'm not blaming the customers here, I'm just saying, that's the reality of the situation. And I accept that it's likely I even do the same thing when the shoe is on the other foot and I'm the customer.

I was just thinking about this not only because of this thread on the cf-talk list but also because I've been preparing to create a video presentation for this contact manager I've been working on. In the thread, Jim Davis points out that most companies tragically overlook usability. It's true, most companies don't do anything about designing for usability (you might call it "ergonomics") in spite of the fact that it's probably the single most important thing you can do period when developing software. Further when they realize that there is a problem, they usually misdiagnose the problem and misprescribe a solution.

AJAX is a great example of this. Companies seeing that there is a problem and misunderstanding that problem have glommed on to the AJAX bandwagon left and right, shouting "give the programmers AJAX! It will solve all our problems!" They have yet to realize that simply putting bells and whistles in front of a bunch of guys who don't know how to do usability in the first place hasn't helped them learn usability at all. Now they just design horribly unusable AJAX applications! They commit heinous crimes against humanity like using CFWINDOW everywhere.

This is good news for me of course, because I spend so much of my time focusing on the ergonomics of my own software. I of course use AJAX or at least AJAX-like features. But I also do my damnedest not to be a man with a hammer, viewing every problem as a nail that can be driven with the same tool. In spite of how much I might use certain specific tools such as the SQL abstraction layer or the XHTML abstraction, there are always cases in which the preferred tool isn't the best tool for the job.

Like I said I hate performance tuning, and I've been doing more of it recently because I've been prepping for this video presentation for my contact manager. I mentioned in a blog the other day that I had tuned the RegionManager in the Members onTap plugin. There I had eliminated several uses of the SQL abstraction layer in favor of storing larger queries in memory and using the ColdFusion server's built in Query of Query feature to pull nested set information to get the ancestors or descendants for a given region. It turns out that simply storing those queries in memory is a notably better tool for the job.

And now I find myself doing the same thing with one of the displays for the contact manager. I had already created several CFC objects to store information about this particular display, which loops over two queries to display information from them. I'd created the CFCs as an alternative method of customizing the display for this page, which then generates XHTML that goes into the framework's XHTML syntax, gets transformed with XSLT more than once and becomes a set of structures before finally being converted into a string and passed off to the browser. That means there were 3 separate ways to customize this page between the CFCs, the XSLT and the XHTML tools.

The problem is all these join-points are creating all the overhead in the display and given that this isn't a page where a user has requested something specific (and would therefore be willing to wait longer), this particular page needs to be faster. So it looks like I'll be moving away from the XHTML library and the associated XSLT (most of which is unused on this page anyway) to simply having the CFCs generate the HTML directly in this case. The CFCs themselves are lazy-loaded and cached once for the entire application, so once I've removed the XHTML the performance should be pretty darn close to the performance for cf templates that use no framework at all.

And over the years, "it's slow" (without any kind of qualification of what they mean by "slow") is the biggest and most frequent complaint I hear from people about the framework. WHAT is slow?! Did you disable the development mode?! What are you using for a server?! (I use a notebook for development and expect it to be slow.) Are you caching any of your display? (Did you know you can cache your forms?) What are you loading? How are you getting it from the database to the browser? What is the user trying to accomplish? How many seconds do they have to wait? (I see people make the same unqualified complaints about the performance of other packages too - FarCry for example.)

And several people have made this comment specifically about the forms tools, which have been performance tuned gradually over time, however... a form is the one place where performance tuning is even less important than anywhere else in your application! The user understands that the system is working for them and they'll wait an extra second or so for the form to load. But even better would be designing systems that reduce their dependence on forms, especially complex forms. The contact system I'm designing provides no less than three separate context-appropriate interfaces (possibly four) for associating a user with an organization. Only one of them even involves a form and that form has only two input elements which incidentally load with lightning speed.

Yes I advocate using the XHTML library for a lot of things, and yes it automatically takes longer than writing content directly to html, but it's also not the best tool in every scenario. I advocate using the XHTML library a lot because it handles a large variety of tasks well with minimal programming work. If it's not suited to a particular task, you just have to go back to more traditional development.

And if you're going to complain about it being slow, for god's sake, give me a clue what the context is, because a) it's usually not as important as it seems and b) if it is important, there's probably a better way to deliver the content (which will sometimes require more development time).

What Am I Looking At?!

So I was just updating the details for the framework on the ColdFusion exchange on Adobe's site. The exchange itself has some features that are a bit outdated, like the list of "supported browsers" indicates versions of IE all the way back to 1 individually, plus WebTV (does anybody still use that?) but doesn't make any mention of Mozilla later than 1 (Firefox for example).

Anyway, a little further down it shows the above select box for the type of extension you're contributing to the exchange. The list includes all sorts of options for what seems to be most Adobe products, not just ColdFusion, so it includes Photoshop, Illustrator, Dreamweaver, Flash, Fireworks, JRun, Director ... you get the idea. Anyway, because it includes all their products and wants to specify many sub-categories (ColdFusion Custom Tags vs. Components vs. whole applications etc) each individual item in the list can get fairly long and many of them get clipped as you see in the screen capture here.

Being a programmer, I was able to right-click on the option for "ColdFusion: Functions, CFCs & Custom Tags: ColdFusio" and select "inspect element" using the FireBug plugin for Firefox and see that the text for that specific option ends with "n Components". But for any user who's either not a programmer or who doesn't use FireBug (for example, a Photoshop contributor), this is a bad thing. It happened because a designer felt that the forms would be more visually appealing if large input elements like that had a maximum width so the whole form is reasonably consistent visually. I don't disagree however, it does create a problem for people who want to use the form.

Although it's not a perfect solution, I have found that both Internet Explorer and Firefox support title attributes on both the select element and the individual option elements. And this is something that's already built-in to the onTap framework when you use the HTML abstraction features, it will automatically add a title to each option and an onchange event that resets the title on the select box when you select another option. This way if you move your mouse over the option or over the select, the "tool tip" created by the title attribute will show you the part of the text you couldn't otherwise read because it's clipped. I thought I'd mention it here for others since its something the exchange team at Adobe hadn't caught on to yet. Anyway the code ends up looking like this:

<select name="x" style="width:50px;"
onchange="this.title=this.options[this.selectedIndex].title">

<option value=""></option>
<option value="1"
title="blah blah blah blah blah blah">

blah blah blah blah blah blah</option>
<option value="2"
title="yadda yadda yadda yadda yadda yadda">

yadda yadda yadda yadda yadda yadda</option>
</select>

Here's a screen-capture of how this works from my day job.

Unfortunately when I use the print-screen button in Windows Vista it doesn't include the mouse pointer -- which makes it really odd that it does include the tool tip from the title, since it's a direct effect of the pointer's placement! Anyway, just imagine that there's a mouse pointer over that highlighted option, showing you that tooltip so you can see the rest of the option text that's clipped by the select element.

Don't Do This

I realize I'm making an assumption here, but I'm pretty sure I know how this happened... They made the interface and somebody said "how do I add a customer?!" The programmer, thinking it was painfully obvious said to himself "what's this ass-clown talking about?! It's right there!" and proceeds to add the obnoxiously large "Add Customer" button you see in the middle, threatening to create a gravitational well that might consume the known universe. "There!" the programmer says, "now he can't bitch!"

The existing "Add New Customer" button in the upper right, however obvious it may have seemed to the programmer in question, is visually married to a couple of unrelated tasks (go home and log out) and buried because it's not only sandwiched between home and log out but also between the sales person's name and the search forms in the bar below. This interface isn't designed in a way that naturally draws the viewer's eyes across the page such that they would see the tools they need in an appropriate order or context. A person looking at it for the first time sees "no customer selected" first, followed by a couple of search forms, leaving the remaining buttons and text above them in their peripheral. So unless you yourself created this page and so have a prior understanding of it, there's not a strong reason to immediately see how to create a new customer.

The phrase on the left, "no customer selected" is where name and basic information about a customer will appear and is a much more logical place for a link to add a new customer. That text is linked, though unfortunately it's not linked to the add-customer task, it's linked to "home". It probably should say "No customer selected - Add/Search" or have the "add customer" button otherwise next to the customer search form.

Don't do this. Don't assume the customer is incompetent when they're confused by an interface about which you have a prior understanding. The end result as you see here might destroy the fabric of space-time and kill us all! Think of the children.

The Invisible Man

We have this problem at work.

Each of our clients have a queue of sales agents. These agents work at different locations and on different teams and are responsible for different kinds of leads. So for example, Bob at the Portland store is responsible for "special finance" leads, while Mary at the Gresham store is responsible for "third-party" leads. And of course a given team at a given location can have multiple agents working those leads and they can be distributed in a "round-robin" fashion where the leads are divided evenly amongst the available agents, or they can be given specific distributions, i.e. 70% go to Bob, 30% go to Mike.

Sometimes the agents will enter these sales leads into the system manually. Other times (and possibly even more often depending on the store and the agent) these leads are entered through an automated process which imports them daily on a schedule or they're entered through some action the user takes on the client's website. To further complicate things, some of these leads come to the client from various "third parties" (who shall remain nameless) and the client can individually configure the third-party provider so that its leads are assigned to someone other than the third-party team, like the special finance team.

Agents individually can be assigned a maximum number of leads, so if none of the agents on the appropriate team can receive any more leads, then there can be a "catch-all" agent to which leads for that team are assigned when no one else is available. If there isn't a catch-all agent for the team, then there can also be a catch-all agent for all of the client's teams.

None of which begins to touch on the fact that if a new lead appears to be from an existing customer, it is supposed to be assigned to the agent who handled their most recent previous lead.

Are you confused yet? You should be.

These sorts of complex decision trees (that really should be flow-charted if you wanted to see what's going on), are the sort of reason we started creating business software in the first place.

So what happens?

The client sets up their teams. They assign Bob and Mike to the third-party team and get to work. Everything is great. Then they hire Tom and add him to the third-party team and everything is still great. Then they move Tom to the special finance team. Then Tom is fired and removed from the special finance team. Soon enough they log a support ticket that looks like this:

"We received a sales lead for Joe Customer from our third-party provider Bilk-Em Unlimited and it was assigned to our agent, Tom, who was fired a while ago and isn't on the third-party team. We've also disabled the Agent-For-Life feature. Please fix."

We actually receive a lot of these kinds of technical support inquiries. It's usually not the result of a "failure" in the lead assignment routine, but rather simple confusion about how leads are assigned and why they got assigned to a particular agent. This happens several times per week, if not daily. So if it's working "correctly", why do we have this deluge of technical support tickets?!

Our new lead on Joe Customer essentially makes him the invisible man. He's out of the loop. Agents don't see him, because he's not assigned to them, particularly when Tom doesn't work there anymore. And if agents don't see him, then they're not working the lead or earning their commissions. The "well oiled machine" our client wants is slipping a gear simply because they can't accurately predict when or why sales leads will be assigned to a particular agent.

This brings us to problem number two. Problem number two is actually described in some detail in a book I'm reading recently titled Influencer. This is a really good book. The problem in particular that I'm referring to is one of coping. As individuals and even as groups we tend to be much better at coping with an ongoing problem than we are at changing the status quo. It's in the words of the famous Serenity Prayer, "God, grant me the serenity to accept the things I cannot change, the courage to change the things I can and the wisdom to know the difference". The problem is that we all too frequently simply assume that we can't change a particular condition (in this case, constant support tickets for software that's working "correctly"), and so we focus too much on "the courage to accept" instead of focusing on "the wisdom to know the difference".

This is actually a much more common problem than you might think. Even amongst people like us who spend our 40hrs or more professionally changing things, we still frequently fall into the trap of thinking "I can't change that". And I want to address very specifically that I think more often than not, we fall into the trap of thinking "we can't change the user's behavior". To some extent I think as programmers we condition ourselves to think that the users are just tragically incompetent and can't really be helped. That's essentially been a mantra at more than one of the companies where I've worked. Hence nobody bothers trying to improve the status quo because everyone's assumed that any effort to do so would automatically fail. And then we fail by omission - by default - because we failed to try.

In our case for the moment, I'm grateful that I'm being given the opportunity to work on this particular problem. In this specific case, the real problem is not that we have tragically incompetent users. Although we may have a few users who are tragically incompetent, incompetence isn't responsible for a deluge of technical support tickets like this one. No the real problem is that we've turned Joe Customer into the invisible man. Yet every time I have a conversation about this with my current boss, what I hear from him is "before, when these tickets came in, I could usually tell what happened pretty quickly", in a manner of sort of oddly pleading for the "good old days" when we could handle massive loads of support tickets for working software. Say what?! You want these tickets?! He doesn't... but by now he's conditioned to wasting time on them instead of solving the problem.

Up to this point any time one of these tickets came in from a client asking about how or why a particular lead is assigned to a particular agent, the other guys on my team would just manually comb through the data to figure it out and explain it to them. It's unfortunate that it hadn't really sunk in that they were spending so much time on such a simple issue and that if they'd taken the time to address the fact that Joe was becoming invisible, they'd have eliminated a large number of those tickets that were taking away so much of their time. As with health or car trouble, often an ounce of prevention is worth a pound of cure.

Imagine for a moment that you've got a big wooden board and on this board are a series of clear plastic tubes into which letters can be placed. Now every single letter is vital to your business, and most of the time everything works great. Letters go into the tubes and the people who need them can see them immediately and grab them out of the tube and work on them. Every once in a while a letter somehow finds its way into a tube on the back side of the wooden board. The system is designed for letters to be in both sides, but nobody really looks at the back side of the board. And part of the problem is that the tubes themselves aren't labeled, so nobody knows who's putting them in the other side or why they're being put there, they just know that those letters aren't being processed. That's bad for business. So the solution we want is to bring the tubes around from the back side of the board and put them on the front and give them clear labels, so that our system is transparent and stops making those occasional letters invisible.

Right now when our automated system assigns a lead to an agent, the information about that assignment only goes into one place - the "lead" table in the database. But the lead table isn't a historical table. And this is another pandemic problem for software, that it doesn't provide adequate historical information. The lead is assigned, but there isn't any information being logged regarding the reason why the system chose to assign it to the agent. Without that log, everyone who looks at it, including those of us programming the system, can only guess at the reason why a particular agent received a particular lead. Any number of things could cause that guess to be wrong, from the agents on a team being changed to number of additional leads a particular agent can receive (which changes every time they close a lead or are assigned a new one).

So the project underway is to add a logging system that will store key information about the lead, the agent, where the agent is located and where the lead was generated, etc. and what precisely the state of the system was at the time which caused that agent to receive the lead. Once that logging system is in place we'll add that information to the existing display for the lead history in our application, allowing the client to see precisely how and why each lead is assigned. This will make the process completely transparent to our customers, allow them to more easily control exactly how their leads are assigned, and free up all of our time to work on real bugs and feature requests.

Transparency makes the invisible man... visible. :)

The one other thing that this new system will require is a method of informing the clients when this new data isn't available that the missing information isn't a "bug" in our system. Here's why. If the client hires a new agent or heck a receptionist and they become accustomed to seeing our wonderful new system and then later open an older lead and where they expect to see "assigned to agent Mike on Special-Finance Team via round-robin for customized lead provider Bilk-Em Unlimited" they instead see nothing, they'll think (and rightly so) that it's a bug! Information is missing! It should be there!

We obviously can't go back and retrofit all our existing leads because we just don't know what the system's reasons were when they were created. What we can do instead is to provide them with a message indicating that "this information isn't available". Hopefully we'll find a better way of describing it, but there needs to be some indication that it actually is working and simply doesn't have that information because the feature hadn't been implemented when the lead was created.

JavaScript and the Art of Motorcycle Maintenance

There's a little-known problem related to ColdFusion's native JSStringFormat() function and its use in html script tags. In the event that a user enters the string "</script>" into a form in your application and that data is later placed into a javascript literal inside of a pair of script tags, it causes the browser to close the script tag early and produces an unclosed string-literal error. For example:

<script language="JavaScript" type="text/javascript">
alert('#jsstringformat("</script>")#');
</script>

This code will cause the browser to throw the unclosed string-literal JavaScript error, and consequently the alert dialog won't display. Now I'm not claiming this is a bug, because technically in most cases functions that perform a similar task for other mediums, such as URLEncodedFormat() or HTMLEditFormat() only escape a given character if it is described by the documentation for the language or medium as a "meta character", or in other words, if it has pertinent symbolic meaning which causes the interpreter to take some action other than displaying the character within a string literal. In the case of JavaScript for example, the backslash, single and double-quotes, carriage return and line feed are all "meta characters" and would be escaped like this "\\\'\"\r\n". Since none of these characters appear in the string "</script>" JSStringFormat doesn't escape them.

Now because it's not very common for users to enter the string "</script>" into an input element, most ColdFusion programmers haven't seen this (yet). It does however present the possibility of allowing cross-site scripting (XSS) attacks. And because most ColdFusion programmers haven't seen it (and because modern browsers are somewhat forgiving about < and > characters in script literals), most programmers don't anticipate it or take any precautions against it. What this means is that very nearly 100% of applications that currently use JSStringFormat() for the purpose of formatting JavaScript string literals are vulnerable to this variety of XSS attack (assuming the server's script-protect feature is disabled, which is usually the case).

For my money, they shouldn't be forced to learn about it to protect themselves. There exists a proven solution to this problem already which can be seen in the way that SerializeJSON() formats strings. The folks responsible for JSON made a smart decision to escape the forward-slash, so the string "</script>" becomes "<\/script>". This is okay because it's a documented behavior of JavaScript that the escape character \ when followed by any other character will treat the following character as a literal value instead of a "meta character". The forward slash isn't a meta character in JavaScript to begin with, so the engine doesn't have to do anything (and it doesn't). Meanwhile the browser isn't seeing the script tag closed early and both the HTML engine and the JavaScript engine are happy, no errors and no XSS attacks.

Now that there are umpteen applications in the wild using JSStringFormat() however, it's unrealistic to expect all the developers who've created them to retrofit them with SerializeJSON() for all their string values or even necessarily to start using SerializeJSON() for new applications. I feel JSStringFormat() should format strings the way SerializeJSON() does. The larger community however mostly balk at this suggestion.

"Hermes Conrad, you are technically correct, the best kind of correct!"
— Futurama

So here is my synopsis of all the arguments against changing the JSStringFormat() function.

  1. the function behaves the way it was designed to behave, in accordance with common conventions for formatting functions - therefore it's the programmer's responsibility to see this coming (subsequent arguments mostly boil down to supporting or justifying this argument that responsibility falls on the programmer)
  2. Nobody said it would be safe in every environment
  3. It's an edge case
  4. JavaScript isn't always output in html script tags (i.e. <a onclick="alert('#JSStringFormat("</script>")#')">show it</a>) or in HTML in general
  5. The fact that SerializeJSON() works isn't proof that the solution is safe
  6. Making JSStringFormat behave differently than URLEncodedFormat or XmlFormat would be worse than the status quo
  7. It might cause a problem later (related to the previous item)
  8. We would have to anticipate the needs of any future browser (again, related to previous item)

And an analogy:

Assumed:

  • four-wheeled automobiles are currently sold without any protection on the front or rear fender
  • occasionally automobiles are damaged as a result of bumping into another automobile on the street - this happens mostly to the front and rear fender
  • an after-market product called a "bumper" can be purchased and installed on the front and rear fender to reduce or eliminate damages from low-speed collisions
  • most car owners don't purchase bumpers in spite of their low cost and ease of installation

Recommendation: Bumpers are cheap and easy to install, manufacturers might install them as part of the vehicle's original equipment, eliminating the need for car owners to purchase after-market bumpers and saving them money on repairs in the long-run from low-speed collisions.

Objections:

  1. Vehicles aren't designed to collide with each other -- therefore it's the driver's responsibility to protect their car
  2. Nobody said cars would be indestructible
  3. It's an edge case (how often do you rear-end someone at under 5mph or vice versa? It's not very often is it? -- the potential however exists nearly 100% of the time you're driving, just as in the case of JSStringFormat() with most ColdFusion applications)
  4. People don't always drive on the street around other cars, i.e. some people like to drive "off-road", an environment in which the bumper isn't so relevant
  5. The fact that many people purchase and use after-market bumpers isn't proof that they're safe
  6. Other vehicles such as boats, motorcycles and airplanes don't have preinstalled bumpers - deviating from the standard would be unexpected and therefore worse than the status quo
  7. People might not anticipate the extra material on the fender and bump into each other more often or catch it on trees, etc.
  8. We can't guarantee that the bumper won't interfere with future developments in the automotive industry

Hence the reason why these objections get my dander up every time.

How NOT to Design a Toolbar (Winamp Browser Extensions)

Okay, so it's true that I am a programmer, and pretty darned advanced at that... however... I've spent a great deal of time thinking about user interaction as well, a subject that it seems most programmers prefer to avoid if at all possible... I'm not most programmers...

A few years back I read Alan Cooper's book the Inmates Are Running the Asylum and I recommend it heartily for anyone in software. When I first started reading it, I thought Alan was being pretty darn harsh. I said to myself, "come on Alan! Surely SOMEONE who was a programmer once, during a full moon when the wind was in the west and mystics called on the ancient sages of the lost civilization of Atlantis for guidance, had a decent idea about user interaction. Maybe it was on a Thursday in Denmark in '87."

Old Alan seemed dead convinced that there's an impenetrable iron bulkhead separating the hemispheres of a programmer's brain, making them physically incapable of predicting the desire and/or behavior of a non-programmer. Wait, I take that back, it's not iron, it's made of one of those strange alien substances that you see on an episode of Star Trek where the engineer has to say "I'm sorry, Captain, we just don't have anything that can penetrate it". And it's locked tight such that not even the smallest and fastest of tachyon particles can eek through around the edges to tickle the neurons at the edge and give the programmer some faintest dream-like sensation that he's receiving signals from afar in Morse code.

I disagree. I believe I personally have the ability to see both sides and I honestly think a lot of programmers could, if they wanted. But the more I've used today's software, the more painfully in-tune I become with Alan's frustration. I've also talked to some other programmers and where Alan was very careful to be PC in saying that programmers aren't to blame and that they genuinely want to create useful, helpful tools for the users, I seem to have met and talked with a lot of programmers who are in spite of the recent interest in "web 2.0" and "AJAX" or "RIA", actively HOSTILE toward the people who're spending good money to purchase their software. (Though honestly, I've seen similar pent-up hostility in other industries, so I'm not certain it's unique to software.)

I seem to be different from a lot of the programmers I've met in that I've never shared or understood that hostility. And any time I've noticed that someone was struggling with an interface I designed, I've given serious consideration to what caused that rift. Frequently that consideration has contributed to a fairly large body of work around the idea of eliminating the frustration with software. One salient example of this actually applies to something I did for other programmers (including myself) recently with this 3.0 release of the onTap framework in which I spent several hours weeding through my own code, replacing instances of <cfmodule template="#request.tapi.xhtml()#"> with <cf_html> just to make it more legible for people. I wonder how many other people in our ColdFusion community or even the software industry in general would have taken those several hours to do that, knowing that the existing code was already working?

In other words, I fixed what wasn't broken. But then I've always fixed what wasn't broken. For that matter, I take issue with the notion of "if it ain't broke don't fix it". Given that notion, we would all still be sitting around with candles and keroseen lanterns, using an abacus to calculate our taxes. Hey! Those things still work! They didn't need any fixing! There are still AMC Gremlins on the road, but I'm not going to drive one.

But that change in particular was a convenience for myself and for other programmers -- it was something to simplify our lives, not the lives of our clients. Generally speaking, the things I do to make the lives of my clients easier take more time and are much harder to accomplish. Which may be another part of the reason why other programmers don't tackle a lot of those interaction issues, because it takes time and given that they're already disinterested, they're even less inclined to spend much time on those endeavors...

But I digress...

I'd been waiting (not very long, but I was) for a winamp plugin for Firefox. Why? I have Firefox open all the time for work, and it would be more convenient to have the pause & play buttons there than to go through the icon in the system tray, which while functional, doesn't provide a very convenient interface via the right-click context menu.

And now it's here! Huzzah! And my god, it's CRAPTASTIC!

For starters, half of the items on that toolbar are things you're not going to use. Skins and Plugins, right off the bat! Who changes the skin for their radio often enough to want it on the toolbar?! Much less the search. I understand that the search feature was probably an outcropping of the ability to search your media library or possibly radio station lists, but it defaults to searching the web! Which you probably already have in your browser! (Yep, defaults matter.) But even if it didn't include the web search, there are buttons on the other side of the toolbar to open the media library where that search would be more appropriate, yet isn't found. (As an aside, who thought building a complete browser into the WinAmp player was a good idea?)

You can't see it in the screen-capture, but there are tool-tips on those buttons on the right, the ones that you can tell from conventional symbols are for "play", "pause" and "stop", you know, the ones you actually want in this toolbar. The tooltips don't display what the buttons do. Instead they display the title of the current song! Umm... Aside from the fact that I'm not sure why moving my mouse over those buttons indicates that I'm interested in the song title moreso than moving my mouse over the toolbar in general, some of those buttons do things that aren't intuitive and could really use to be labelled.

Just to the right of the "next track" button, there's a button that looks to me like "eject", which I thought was odd... It doesn't eject the CD tray like I expected, it opens the file dialog for you to select a playlist. Great IDEA! Awful execution! Label the button for starters... but then there's the ShoutCast item to the left, which is also part of what I was actually interested in a WinAmp toolbar. That lets me switch the radio station (which I should but can't also do from the previous / next track buttons, since my playlist contains all radio stations, instead of individual MP3s). The open menu in the above screen capture is the ShoutCast menu, but let me rephrase, it almost does what I want. It does let me select the station, but there doesn't appear to be a way to edit the list of available stations, and they're not tied to anything significant or useful, like oh I don't know say... a playlist? Or maybe even stations I've listened to recently?

The "stations I've listened to recently" would be nice, like the "files I've edited recently" that we get in things like Photoshop or Word. It's also something I've integrated into the contact manager I've been working on this past year, particularly uncommon amongst web applications. But to simply slap a menu of radio stations up there in such a random and hideous fashion is just cruel and unusual. Let's let them change the station! To a predefined set of random stations we choose in various different languages they may or may not speak. WTF?!

Give me a list of recent and/or playlist items, let me change the playlist, label the buttons and over there on the left where you're going to remove all that crap nobody will use, add in a HUD for the title of the current song that shows the media search to add items to the playlist when you click it.

If I'd been paying closer attention, I'd have expected these issues, since they were already there in the Internet Explorer toolbar. Oddly, although the IE toolbar was available first, it seems pretty obvious the folks who work on WinAmp are Firefox fans because the IE toolbar has a different set of graphics with really bad anti-aliasing. Maybe what WinAmp needs is some good stiff competition. Someone who knows how to create a decent interface.

So okay, this article isn't related to anything specific with regard to the onTap framework or even ColdFusion programming. It's just a very good example of very bad interaction design and I think programmers in general (self included) can use to learn from these kinds of mistakes. These are issues that affect us daily. An interface that keeps tools you rarely use constantly in your face for example, like the skins & plugins options in this toolbar aren't helping anyone. They're at best a distraction from the task at hand most of the time and actually, empty space in the interface would be preferable to distracting people with things they don't need. And a lot of the ColdFusion software I've worked on over the years suffers from that same issue, so I think it's a good thing to remember when we're designing our software. A fly-out menu containing lots of options for different things you could do for example might not serve the user as much as a link to the most frequently used item and neighboring link to a page containing navigational access to less frequently used tools. There may be situations in which the fly-out menu is really useful and makes a lot of sense, but most of the time I would wager if you can avoid it, your users will thank you.

Save Your Work or Throw It Away -- pheh -- same difference!

Don't get me wrong, I'm grateful to have open source software... I just thought I'd point this out for whoever might not have been bit in the ass by this yet:

These are the default keyboard shortcuts for CamStudio. Fortunately I wasn't bit by this... Unlike most users I checked the keyboard shortcuts before I used it (which I normally probably wouldn't have, but CamStudio is a really small program and there aren't very many options). I deliberately set ctrl+shift on the "cancel recording" keyboard shortcut to prevent myself from accidentally throwing away my work when trying to save it.

There are a number of problems with this. First, the f9 and f10 keys are immediately next to each other, so it's just a matter of being a simple "typo" that would cause you to lose all your work. Just be in a little bit of a hurry or mildly distracted and POOF! All gone.

Second the application doesn't need a "cancel recording" hotkey. When you hit f9 to stop & save, by default it asks you for a file name and there's a "cancel" button in that dialog that works just as well. Further, even if you set the preference to have it not show you that dialog when you stop recording and save it automatically with a file name derived from the date and time, all you have to do is open the directory where it saves them and delete the file. And given the frequency with which you're likely to delete your work and the fact that you wouldn't even need to unless you'd changed the preferences, I'd say that's fine.

Finally, if they really insisted on having a keyboard shortcut for "throw it away", they should have put it half-way across the keyboard or added those ctrl+shift modifiers to it by default so that "throw it away" would require a different thought process to access it. Personally I prefer the ctrl+shift modifiers because it requires 2 hands and that way you're not likely to accidentally throw it away by lazily laying your hand down on another part of the keyboard in the middle of recording. Yes you can still habituate yourself to throwing things away and frustrate yourself by doing that out of habit, but you'd at least have to initiate the habit, so it'd be like smoking. While it may not be easy to quit smoking, you never find yourself smoking a cigarette accidentally.

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.5.006. | Protected by Akismet | Blog with WordPress