Saturday, November 25, 2006

Bad usability is like a leaky pipe or driving or a road riddled with potholes.

I am famous for my car analogies. Most people get them immediately because they all have experience with cars, and I've been able to come up with some good examples that helped people understand some really complicated things.

Here's a great non-car analogy from 90 Percent of Everything: bad usability is like a leaky pipe.

The author explains that if there are too many opportunities for the user to get lost or make mistakes, then you might not see as many customers completing the transactions you were hoping for at your web site. This is applicable to applications too.

The article includes a graphic that shows how a lot of water might drip out on its way to the tap. Each drip represents a usability "leak" such as "What does that error mean?" and "What do I do next?" What you get at the end is not the complete volume that was supposed to come through but just the amount that managed not to drop out along the way. Imagine losing 60% of your customers simply because they got lost on the way to completing the sale! What is the likelihood of them coming back for more?

My car analogy would probably be about potholes, and I'd say something along the lines of...

If the drive to your store is always characterized by potholes, detours, traffic, or other undesirable incidents, then drivers are likely to choose much more comfortable alternate destinations even if those destinations only offer a portion of the things the original destination promised.

In other words, your store might lose a sale, and maybe a customer for life if your product's usability stinks.

It's bad enough when heavy rains cause the potholes, but it's worse when the potholes are of your own creation.

It's easy for a programmer to become oblivious to usability holes. The assignment might have been broken down into tangible sub-tasks, and somewhere along the way, there is no check to evaluate the whole solution to see whether it is "correct" in all dimensions. It may employ the best possible algorithms and a pass a peer review, but what about the user's review? Does the solution work for the user?

Users don't care why your program is fast or slow, they just know that it is.

Users don't care why something can't be clicked or can't be scrolled, they just know that they'd like to click or scroll those things.

What they care more about is not whether your task was completed on schedule and budget, but whether theirs will be.

It's especially bad when a competing product or service might do a better job at providing those same features, because the user will need more justification to keep using yours. As stated by Raymond Chen at The Old New Thing blog, "it doesn't matter how great your 1.0 system is if you don't survive long enough to make a 2.0."

No matter how magnanimous your supervisor claims or wishes they could be, the reality of life is that you have to meet deadlines and get some code turned in. Do what you can to ensure that you are truly solving the customer's problems and not just your own, or else there may not be any customers/clients, and eventually no deadlines at all because there's no product to work on.

Wednesday, November 01, 2006

Software is like carpentry.
Given the user's requirements, programmers can probably build whatever is being asked for. It might look ugly, but if that's what the end user wants, and they're happy with the resulting product, then success, and profit! Sometimes you create a thing of beauty, and then success, and profit! In general, nobody wants to make something ugly, but circumstances might take that end result out of our control. (I refer you to the numerous articles at The Daily WTF for some examples)

One of the advantages of working with wood is that you can handle it pretty easily and fix constructions issues quickly. Things with steel are not the same. Steel isn't something you just casually pick up in your car or truck at a construction store, and it requires lots of other machinery (and people) to make things with. Now there's nothing wrong with steel as a raw material, but it means that you need to have anticipated a lot of things in advance and make some very great plans. Unfortunately, it also compromises your ability to adapt to changing requirements (and externally imposed limitations such as building codes), and it's entirely possible that if the design and plans are too inflexible, then you're going to be forced to generate a result that's not making everybody happy.

Building software is a little like that. Large projects need to be planned out well, the design needs to be in place and employees need to have some semblance of a strategy so that the business managers can figure out how everything gets paid for. However, one thing we have in software that they don't have in architecture is that we don't build our skyscrapers with steel.

The pliability of our raw material is great. It means we can still be responsive and address unforseen issues with less hassle than if we had built things out of steel. It doesn't mean that we can or should build our skyscrapers crooked on a whim, but it does mean that programmers have some room to make adjustments.

My big deal about this wood example is that your end result is what matters. Sure, it needs to be on schedule and budget, but it also needs to solve the problems that it was supposed to. And it should solve those problems well and your end users should be happy.

Instead of coming up with reasons to disprove why a new feature can't or shouldn't go in, just listen to your customer and take notes. You don't have to come up with the answer in that same instance, but just make sure you properly understand the problem being described. This is just as much about people skills as it is about technical prowess. Quite often, a non-technical user has a slightly different understanding of your system, and the solution might just be to move some UI elements around, or add new parameters.

One of the things that I do in my own coding is to account for future extensibility right there in my functions. For example, passing objects and data structures gives you a silent way to upgrade your system. A trivial example would be a function that calculates averages. An interface like:

float CalcAverage( float f1, float f2, float f3, float f4 );

is limited to only handling a fixed set of inputs. If your needs change, you'll have to track down all the places where this function was called and update them. If it's a large project, you might even miss some modules and be forced to revisit your updates later.

Worse yet, someone (hopefully not you) might cut-and-paste from this function to create variants for other uses. This means that certain kinds of bugs or other problems in the original can propagate to other functions, and the QA complexity has just increased.

Consider an interface like:

float CalcAverage( FloatArray f );

It's much more flexible. I'm not going to explain why because I didn't intend this to be that basic of a programming chat.

Build a reasonable amount of flexibility into your systems at design time. You'll greatly reduce the ramifications of changing requirements. It's much easier to maintain this kind of code, and you'll definitely get more work done.

Going back to the wood vs. steel analogy, software solutions have a lot of room for flexibility. Unlike the business of building skyscrapers, we have more freedom to change lots of things as we go along. It doesn't mean that we should (because that might throw the project way off schedule, or our product might lose its focus), but we should be responsive to the end user's needs and the project's goals. There's no point in releasing something useless, is there?