Thursday, September 14, 2006

An Overview of TransformAble

My latest article provides a general overview of a project I'm working on with my colleagues here at the Adaptive Technology Resource Centre. I've also included some notes at the end about the process of integrating this technology into the Sakai Collaboration and Learning Environment.


What is TransformAble?

TransformAble is a set of Web services which can be used by any suitable Web application to deliver a more accessible and customizable user experience. The TransformAble services modify a site's user interface and content resources in order to accommodate the individual needs and preferences of each user. These services enable Web sites to enhance and rearrange their appearance, layout, and structure. Such transformations provide customized accommodations including large type and high contrast colour schemes, simplified site navigation, accessible alternatives to audio or video content, and more.

TransformAble works with the ISO standard AccessForAll model, which provides a common representation for both user preferences and resource descriptions. AccessForAll is used by the services to match the user's needs with the most appropriate resources and presentation available. AccessForAll was designed for interoperability, and enables preferences to be used portably across compliant systems.

TransformAble is being developed by the Adaptive Technology Resource Centre at the University of Toronto. The project consists of three Java-based services which are available as open source under the MIT license: PreferAble, StyleAble, and SenseAble.

PreferAble

PreferAble provides an easy-to-use Web interface which enables the user to edit and store their preferences. PreferAble walks the user through a series of questions about how the application should appear and behave. This allows the user to configure preferences including screen enhancements such as larger type and higher contrast colour schemes, preferred language, control preferences, and required alternatives to multimedia content such as captions and audio descriptions.

StyleAble

StyleAble performs a range of display and structural transformations on any well-formed Web page. These transformations can be categorized into two types: 1) generation of custom style sheets, and 2) document transformations.

Style Sheet Generation
StyleAble's CSS generator can create customized style sheets based on a user's stated preferences, allowing them to control the overall appearance of the site, including the font size, face, foreground colour, background colour, highlight colour, and link appearance.

Document Transformation
Document transformations provide augmented views of a document which help users to navigate and understand the content more easily. This includes the on-the-fly creation of a table of contents or a list of links, as well as the ability to reduce the density of the content by hiding and showing specific levels of detail.

Unlike SenseAble, the StyleAble service doesn't require metadata or a content repository. It uses the structure of well-formed HTML documents to provide information about how to perform these transformations.

SenseAble
[Note: we've recently chosen to not integrate SenseAble into Sakai.]

The SenseAble service works alongside content repositories which contain multimedia resources and associated metadata in the AccessForAll format. This metadata helps to describe the characteristics and accessibility of a particular resource, including the potential alternatives which may be available for it.

Based on this information, SenseAble matches the available resources with the accessibility needs and preferences of the user. This process may involve substituting, augmenting, or re-aggregating portions of the content to make it more accessible to the user. For example, if a user is viewing a video resource and is deaf, hard of hearing, or is working in a noisy environment, SenseAble can match this need with any associated captions or sign language resources which may be available for the video. SenseAble's matching engine determines the availability and appropriateness of content alternatives, ranking them based on user preferences. The content aggregator in StyleAble can work with audio, video, textual and SMIL content to build alternative versions of the resource that are more accessible to the individual user.

AccessForAll

AccessForAll is a multi-part standard consisting of the Personal Needs and Perferences (PNP) which encapsulates user preferences, and the Digital Resource Description (DRD) which describes content resources. The DRD describes how a resource is perceived, understood, and interacted with. The TransformAble services depend on the AccessForAll to provide a standard means whereby resources are matched to the accessibility needs and preferences of a person.

The concepts behind the AccessForAll framework were originally developed by the IMS Accessibility Working Group and is now in the process of becoming an ISO standard. The ATRC has developed a Java-based implementation of the PNP and DRD models for use by PreferAble, StyleAble and SenseAble.

TransformAble and Sakai

I'm currently in the process of integrating the first two services, PreferAble and StyleAble, into the Sakai portal. PreferAble currently consists of a JSF-based Sakai tool and a PNPPreferences service available through the ComponentManager which will enable any tool to store and retrieve preferences in the PNP format. StyleAble has also been built as a Sakai component service, and I'm currently in the process of adding hooks into the Charon portal to enable the inclusion of custom, preferences-driven style sheets throughout Sakai. We're still investigating where SenseAble best fits into the Sakai architecture.

Our plan is to release PreferAble and StyleAble as contrib tools sometime after the Sakai 2.3 release in October. This will give the community time to try it out and provide us with feedback. As we refine the TransformAble services--and if the community finds them valuable--we will plan to include it as provisional in time for the 2.4 release.

We're still in the process of preparing the source code for public release and setting up a public Maven 1.0 repository for accessing the TransformAble jars. In the meantime, I've really been enjoying working with the well-factored, Spring-based Component API in Sakai. The community has been incredibly responsive to changes we needed to make--such as removing the tool title and navigation iFrames--and I'm very grateful to Chuck Severance and Gonzalo Silverio in particular for their feedback and hard work. It's my hope that TransformAble will help to augment the hard work already done to make Sakai more usable and accessible to a broad range of users, and will lay the groundwork for a more flexible, adaptable user interface in the future.

Tuesday, August 22, 2006

User Interface Design Patterns

Welcome Back

It's been a ridiculously long time since I last posted to Code Scents. Since returning to the Adaptive Technology Resource Centre in December, I've been pleasantly busy becoming a member of the Sakai community, reading a lot about usability and accessibility, and writing plenty of music. It's been a bit of a blur.

One of the projects I'm currently involved with for Sakai is creating a library of User Interface Design Patterns with a group of designers from around the world. It's an experience that promises to teach me not only a lot about design, but also about the potential and pitfalls of doing collaborative work remotely with a disperse group of contributors. Given my interest in agile software development, I'm quite pleased to be working with people in the Sakai community who have a lot of experience with this sort of thing.

Design Patterns for User Interface Design

Interest in pattern languages has grown among interaction designers in recent years, and there are a number of books and Web sites dedicated to the subject. Design Patterns were first described in the work of Christopher Alexander, an architect who built a catalog—or pattern language—of general solutions to recurring architectural problems which could be adapted by other architects for their particular situations. His pattern language identifies patterns in both small- and large-scale structures, from the size of trim in a house to urban planning designs. More recently, design patterns have been widely adopted as a way of describing effective object-oriented software architectures. Kent Beck's article A Short Introduction to Pattern Language provides a great overview of Alexander's work and Beck's own intentions in constructing a pattern language for sofware architecture. Given my interest in both software patterns and usability, the notion of applying patterns to user interface design seems to me a very useful—if potentially incomplete—way of communicating design knowledge and practices.

In her book Designing Interfaces, Jenifer Tidwell describes what a design pattern is in the context of interaction design:

"... patterns can be a description of best practices within a given design domain. They capture common solutions to design tensions... and thus, by definition, are not novel. They aren't off-the-shelf components; each implementation of a pattern differs a little from every other. They aren't simple rules or heuristics either. And they won't walk you step-by-step through an entire set of design decisions—if you're looking for a complete step-by-step description of how to design an interface, a pattern catalog isn't the place!"

Sakai has a very good Style Guide which documents a number of practices and guidelines for building consistent user interfaces. However, the diversity of appearance, internationalization and behavioural needs of Universities from across the world have caused some degree of contention around the notion of an entirely prescriptive approach to user interfaces. The Sakai community has identified a need for more general or customizable advice on user interface design, and this is where the design patterns work comes in. They have the potential to provide, as Tidwell said, a description of best practices for user interface design in Sakai, rather than a prescription for exactly how these solutions should look. I see these design patterns as a way for the community to pool its knowledge and experience around UI design into a single library of patterns which are flexible enough to accommodate the diverse range of needs. Nonetheless, behavioural and appearance consistency is an essential quality of a useful interface, and design patterns by nature don't address consistency, nor do they grant authority to a single design. My hope here is that the design patterns library will provide a rich source of solutions to common UI design problems in Sakai, and that a renewed Style Guide or similar replacement will take these patterns into account when defining specific directions for maintaining consistency across the constellation of Sakai tools.

Documenting the Existing Pattern Libraries

I've been researching the topic of design patterns for user interfaces and found several of resources that are worth looking into:

Yahoo!'s Design Patterns Library
http://developer.yahoo.com/ypatterns/atoz.php

Jenifer Tidwell's Designing Interfaces
http://designinginterfaces.com/

Martin van Welie's Web Design Patterns
http://www.welie.com/patterns/

Sari A. Laakso's User Interface Design Patterns
http://www.cs.helsinki.fi/u/salaakso/patterns/index.html

Coram & Lee's A Pattern Language for User Interface Design
http://www.maplefish.com/todd/papers/Experiences.html

... and the team of grad students at UC Berkeley who created the Web Patterns Project
http://harbinger.sims.berkeley.edu/ui_designpatterns/webpatterns2/webpatterns/home.php

I particularly appreciate the detailed content and comprehensive set of patterns in Jenifer Tidwell's book (her Web site is unfortunately more brief) and the clarity and concision of the Yahoo! Design Pattern Library. The inclusion of an Accessibility section in the Yahoo! library is fantastic. We're still in the process of refining the format of Sakai's design pattern library, but I hope it will reflect the amount of detail provide in Jenifer Tidwell's "Why" section while maintaing the simplicity of Yahoo!'s structure.

Friday, March 03, 2006

Elements of Web Application Architecture

This article consists of a few in-progress notes I assembled in preparation for a project meeting today about application architecture. While still rough, they outline and elaborate upon a number of design elements that I think can contribute to a successful and responsive web application architecture. As usual, I'm heavily indebted to the writings of Rod Johnson and Martin Fowler.

1. A strong, domain-driven and object-oriented model
Domain models represent the core, object-oriented building blocks on which an application architecture is structured. Model objects represent fine-grained objects, often mapped to database tables, which contain the essential data and behaviours of your application domain. In the past, the status quo of J2EE architecture has always dicated that model objects should serve as simple data holders instead of encapsulators of behaviour. Why have rich, behaviour-driven data models been so consistently overlooked design in J2EE architectures? As I see it, there are a couple of legacy designs which served to limit the way in which data objects can be designed:

a) EJB entity beans
Due to constraints in the EJB approach, entity beans needed to be just data holders rather than full-fledged objects responsible both for encapsulating data and providing business logic for working with that data. This constraint forced developers to inappropriately push domain logic up into the service tier as session beans. The problem with this design is that it blurs a critical distinction between fine-grained business logic (which rightfully belongs in the model) and coarse-grained application logic suitable for the service tier.

b) Hand-rolled DAOs and Direct use of JDBC
The use of direct SQL calls and ad-hoc data access objects (DAOs) tend to lead towards an architecture that emphasizes the underlying structure of the database, causing data objects to be less like real-world objects. The overhead of manually maintaining the kind of object graphs required by real business logic is often too complex for ad-hoc DAO objects, thus leading back to this problem of model objects being misused as simple data holders.

2. A clearly defined and widely useable service layer containing higher-level application functionality
The service layer packages up broader application functionality, consisting of logic that depends on the composition of several domain objects. This layer generally contains the code that does the real work of the application, suitable for use by clients in the presentation layer.

3. A razor-thin presentation layer
To satisfy the goal of creating reusable services, the servlet tier needs to be thinned out considerably, and its responsibility should be reduced to three main tasks: a) parsing and structuring user input; b) calling into the service tier; and c) packaging up output to the user. The workflow for both of these tasks is further facilitated by a web MVC framework.

4. A consistent controller framework to manage the view
In the current J2EE web tier landscape, there are two main types of technology available for designing a well-separated view and controller layer, distinguished largely by the level at which they model user interaction:

a) Request/Response-driven MVC Frameworks
Examples: Struts, Spring MVC, WebWork

This type of tool closely models the servlet lifecycle, usually providing a fairly thin controller layer used to pull values from the user, process commands and forms, and invoke data validation. The controller layer then passes off the resulting data to the view tier--implemented as templates using JSP or Velocity, for example--for rendering.

b) Page- or Event-driven Frameworks
Examples: JavaServer Faces, Tapestry, Wicket

This type of framework attempts to model the workflow and structure of reuseable page components as real objects. The goal is to facilitate the composition and reuse of user interface widgets in a similar manner to many desktop UI toolkits such as Swing. These tools tend to abstract the processing of request/responses in terms of higher-levels events.

5. Clear separation of dependencies between application tiers
Preserving the separation between tiers of the application can be facilitated with a combination of design techniques and the use of an application framework and inversion of control container such as the Spring Framework. From a general perspective, there are a few concrete things that can be done to improve loose coupling of objects:

a) Separate your concerns: each object should be clearly focussed on the details particular to its job. It shouldn't be encumbered by logic or API that extends outside its domain.
b) Reduce overall dependencies of business logic on non-core APIs (including Servlets and JAXB)
c) Inject dependencies rather than hard coding them: don't wire up services or do lookups in code, let a framework help you out so that your code can easily be used in other contexts.

6. Testability
Avoid tightly coupling business logic and services to third-party APIs and to themselves. If you can't test your application using a diverse set of testing techniques--many of which require working with isolated units of behaviour--because of architectural constraints, your application won't work. Period.

The End Goal: Flexibility and Resilience
In this context, when I use the word "flexible" I don't mean as a synonym for "power" or "control," but rather in a literal sense: Successful architectures need to be able to bend and flex to accommodate unforseen changes. Constrast this idea with the notion of architectural resilience, which involves a fundamental consistency and vision that remains coherent and useful despite constant change. Both are essential for a successful architecture.

Tuesday, January 31, 2006

From Magic Bullets to Puzzle Pieces

Arising from a discussion about expanding the unit testing activities on our current project, a colleague of mine sent along an excerpt from Robert L. Glass' Facts and Fallacies of Software Engineering. His impression was that this book provided a clear argument against the need for us to write comprehensive software tests. I don't agree, and my sense is that Glass' comments in Facts and Fallacies are not intended as an attack against the practice of unit testing in particular. This article is an attempt to work through some of the common misconceptions about test-driven development, articulating the advantages of testing as I have experienced them in practice. Although I haven't yet had a chance to read the whole Facts and Fallacies book, I will quote from the portions of the book that address the issue of testing as they were forwarded to me.

The Successful Software Puzzle

My main position here is that comprehensive unit testing delivers a number of key benefits to the software development process, making it an indispensable tool for writing better software. To understand the true value of unit testing, it's essential to move away from the dogmatic notion that test-driven development is a "methodological magic bullet" (as some skeptics have put it), seeing it instead as one technique among several that are highly effective in producing successful software. One piece of the puzzle, so to speak.

The argument against unit testing, as it was articulated to me at a recent project meeting, is that one-hundred percent test coverage is not sufficient for catching all program errors. I'm not sure this argument makes much sense, as most would agree that there is still significant value in catching some percentage of bugs rather than doing nothing at all. But before we get into the numbers, let's start by looking at what kinds of errors generally occur in software, and how other agile development techniques can help to augment unit testing and further reduce errors.

In his Fact #33, Robert Glass states that, based on his own personal research, there are essentially two kinds of errors which can occur in software. He says:

"I was working in the aerospace industry at the time and I had access to lots of error data from lots of real aerospace projects. I decided to examine some of that error data, one error report at a time from the point of view of this question: Would complete logic path coverage have allowed someone to detect this error? ...

The answer, as you could already guess from my earlier treatment of this topic, was all too seldom "yes". There were a large number of errors that thorough structural testing would not have been sufficient to detect. As I looked at error report after error report, those particular errors began to separate themselves into two major classes. Those two classes were:

"1. Errors of omission, in which the logic to perform a required task was simply not in the program.
2. Errors of combinatorics, in which an error would manifest itself only when a particular combination of logic paths was executed."


In the first case, it's unlikely that unit tests are sufficient in themselves to catch an error if the programmer was not aware of the need for the logic in the first place. Fair enough. So if we look at unit testing as one piece of the puzzle, what other techniques are available to help prevent this type of error?

In my mind, user-driven requirements and acceptance testing provide some support in this regard. Agile development shifts the emphasis of requirements definition away from time-consuming and often-ignored paper documentation and towards a more customer-driven approach. Tasks are defined and prioritized by the users, allowing them to participate fully in the process of shaping the software and in helping verify its success. With the customer driving the features, important business logic is less likely to be omitted by the developer, and if it is forgotten, is more likely to be caught in testing.

In the second case, Glass refers to the fact that individual logic path tests aren't able to catch bugs which rely on the user triggering certain combinations of behaviour or functionality to make themselves known. Certainly, every software developer has encountered these kinds of errors and is aware of the difficulty in tracking them down. Once again, this is a case where other techniques work in concert with unit testing to reduce bugs. While unit testing focusses on verifying individual classes and methods in as loosely-coupled a fashion as possible, user acceptance tests help to verify that large-scale usage patterns are correctly handled by the application. Although it is impossible to test all of the possible permutations and combinations of an application's functionality, acceptance testing ensures that the most important types of behaviour--those paths which the customer determines are essential to their work--are correctly supported.

Once again, I don't believe that Robert Glass is talking about the failures of unit testing in particular here. Fact #33 ultimately states what we know from experience: that software is highly complex and, as a result, preventing bugs is one of our most difficult challenges. It takes time, effort, and skill to write software that meets the needs of its users reliably. Glass reminds us that testing needs to be taken seriously and should be considered from several perspectives--from the lowest level of individual units through to broad user acceptance tests--throughout the software development lifecycle. Glass himself says:

"The fact of the matter is, producing successful, reliable software involves mixing and matching an all-too-variable number of error removal approaches, typically the more of them the better. There is no known magic solution to this problem."

Okay, so let's put this issue of the magic bullets to rest once and for all. It's a cynical conclusion to assume that unit testing is just another snake-oil sales job, promising one more cure-all for the ailment of software complexity. This notion is perhaps driven by the hype currently surrounding agile software development, and has lead some people to think that Extreme Programming (XP) is like many of the other approaches to software we've been sold over the years: a so-called "big M" methodology. But at it's core, XP is not a methodological prescription. In reality, it attempts to shift the focus of the development team to a number of proven techniques that have been successful in the past, regardless of methodology. What XP brings is the recognition that certain best practices support each other and work best in combination. The true value of agile development is that it challenges us to find the simplest, most effective techniques for creating successful software, and to recognize their benefits as an integrated whole, rather than in isolation. That's not to say that many agile techniques, including unit testing, can't be used on their own, but that their full value isn't always apparent without other supports in place.

Returns on Testing Investment

That having been said, let's go back to looking at unit testing on its own for a moment. I certainly agree with my colleague's underlying point that it is important to think critically about the benefits and costs of unit testing. Assuming Glass' informal study is accurate, is unit testing really worth its cost? Glass believes that structural testing of any kind has the potential to catch only about twenty five percent of all errors in a software product. He found that:

"Errors of omitted logic represented 35 percent of the database of errors I was examining... Combinatorics represented a quite surprising additional 40 percent. Thus 100 percent structural test coverage, far from being a step toward error-free software, is an approach that is seductive but insufficient - insufficient at the 75 percent level (that is, complete structural coverage will still guarantee us the detection of only 25 percent of the errors in a software product)."

The problem here is that error reduction isn't the only benefit provided by a comprehensive suite of unit tests. These numbers simply don't reflect the true value of unit testing, since they ignore the several beneficial roles that unit testing plays in addition to the reduction of errors. Here is how I see it:

1) A comprehensive test suite eases the process of tracking down and fixing bugs once they've been discovered. Of course, unit tests are no substitute to user-level testing, but when bugs are encountered by users or testers, an existing test case serves as an effective fixture for quickly writing new tests to prove the existence of the bug. Once the test has been written, the unit tests provide immediate feedback about the bug's status and help to identify regression errors that may occur later in development.

2) Testing improves code design. Comprehensive test coverage demands implementing code in smaller, simpler units. This benefits overall class design and facilitates refactoring. Even more importantly, the process of testing classes in isolation requires a stronger emphasis on loose-coupling and coding to interfaces, two key ways to improve the flexibility of objects. The impact of testing on the design process is an often-underestimated feature of test-driven development.

3) Unit tests are a more effective way to articulate our intentions and expectations of how a class should be used than documentation alone. Well-written tests represent the first client for the code, and help to explicitly declare certain assumptions made while the code was written.

So, the benefit of unit testing not only includes a reduction in program errors, but also provides a useful infrastructure for fixing bugs and catching regression errors, encourages better code design, and a is clear way of articulating intentions to other developers. As I see it, unit testing provides much more than a 25% return on my investment.

Once again, I want to be clear here: I don't see unit testing as a methodological "magic bullet." Software development is complex, and requires the integration a number of techniques and approaches to be successful. No tool or methodology can substitute for the knowledge and experience of good developers. But unit testing has proven itself to be an extremely valuable technique, and I have come to view writing tests as one of the fundamental responsibilities that all programmers hold. Interestingly, I don't think Robert Glass disagrees with me on this point, so I'll let him have the last word here. In an article in the IEEE Software journal, Glass states:

"Unit testing: Few, other than formal-method and fault tolerance zealots, will argue against unit testing. It might well be the most agreed-upon software best practice of all time."

Well said.

Wednesday, November 02, 2005

Agile Architecture and Optimization

In part, this article is a response to an ongoing and very enjoyable discussion I've been having with my uncle, a filmmaker, academic, and C++ programmer who has been developing software since before I was born. Although we differ in our emphasis on the role that simplicity, elegance, and design patterns play in a successful software project, I respect his perspective on programming very much.

At one point in our discussion, he at least partially adopted the role of devil's advocate with me, criticizing object-oriented development as a "straight-jacket" architecture which leads to fundamentally unchangeable inefficiencies. I don't think he truly believes this, but he definitely believes in the need to get "down and dirty" with code in order to ensure application performance. Based on my perspective as an agile software developer, I have attempted below to articulate how architecture and design can facilitate the integration of highly optimized code in a successful object-oriented software project.

Clearly, this is a work in progress and will be refined as our discussion continues.

Architecture

Architecture must be flexible and easy to change. It should never represent a straight jacket which prevents the developer from meeting the user requirements.

A refactorable architecture is one that can be radically and iteratively changed based on user requirements, including the need for quicker performance. Refactorable architectures have two main prerequisites: 1) modularity, and 2) testability. A modular architecture decouples a specific algorithmic approach or implementation from the rest of the application, making it easier to adapt the implementation based on new user stories or the need to optimize performance.

I strongly believe that object orientation—and the best practice of coding to interfaces—provides one very effective key to modularity. Indeed, both a good object-oriented language and application architecture should support the ability to plug in the best possible implementation, even if it exists outside of the language or design paradigm. In rare cases such as signal or image processing, there may be a need to use highly optimized procedural or assembly code, and every prominent object-oriented language provides for these bindings. Clear examples of this are the ability to integrate C code directly into C++ or Objective-C classes, and the ability to make calls to native C libraries in Java. Accordingly, a good architecture should shield these implementation specifics from client code and minimize the impact it can have on the rest of the application.

Secondly, an easy-to-run suite of unit and acceptance tests are fundamentally necessary to enable agile refactoring of the whole architecture. Without these tests, it quickly becomes impossible to change core aspects of the application design in order to improve performance or in light of new use cases. A test suite provides a harness to ensure that the agile development cycle—including benchmarking and optimization— is workable and more easily managed.

It is my sense that in most large applications, the foremost cause of performance problems is poorly designed and overly-complex architectures, not individual code implementations. The J2EE EJB specification is a prime example of this principle. While application server vendors such as IBM and BEA work tirelessly to optimize their implementation, the overall specification of EJB is at the root of many performance problems in J2EE applications. Assuming capable and diligent programmers, efficiency at the unit level is a natural part of the thought process, while architectural efficiency is too much a part of the big picture to be obvious while implementing individual pieces of code. Developers need to constantly consider and refine the overall shape and design of the application throughout the development process.


Performance, Efficiency, and Optimization

Optimization should be a product of evidence-based analysis, driven by user needs. Software is a multi-dimensional discipline, and performance is one of several important dimensions.

For desktop and rich web clients, the speed and responsiveness of an application is critical to its success. As a result, performance is part of the application's overall usability. In a customer-driven process, this means that it is the user who decides how efficient and responsive an application should be, not the developer. Focussing on code optimization early in the project makes it all too easy for developers to lose themselves in a kind of efficiency myopia, leading to a compromise of user requirements in exchange for optimizations which ultimately may have no real-world benefit.

Given this problem, there are two essential aspects to effective performance optimization: 1) concrete performance specifications decided by the user, and 2) metrics and benchmarks by which to measure the actual performance and effectiveness of an optimization. Real-world, evidence-based observations must drive the process of optimization, not theory. Rod Johnson provides a clear overview of how to do this in his J2EE without EJB book.

Ultimately, performance is only one requirement out of many. Although code-level efficiency may be a particularly interesting aspect of software development, that in itself doesn't necessary make it more important. A balance must be struck between a number of considerations in order to ensure a successful software product. It is the developers' responsibility to balance the need for a performant application with the ability to scale the code to future needs, to avoid bugs, and to develop the software on time and within budget. All of this should be driven by user needs, not developer interest.

The bottom line is that an application must provide the necessary features, responsiveness, and stability at the right price. In my mind, this is accomplished by letting the customer drive the requirements, by emphasizing a modular, changeable architecture, and by ensuring that tests and metrics play a central role throughout the development and optimization process. Agile development and object-oriented design can play a key role in ensuring this success.

Wednesday, August 10, 2005

Don't Click It

A former colleague of mine at the University recently sent along a link to dontclick.it, a Web site that bills itself as an experiment in new user interface concepts. I found the site intriguing, and recently spent some time working through its material and thinking about the consequences of this approach for the user. The following article uses dontclick.it as a springboard for thinking about some of the essential principles of Web user interface design.

Questioning Existing "Habits"


The premise of dontclick.it is to entirely replace the action of clicking the mouse button with UI widgets that can be activated by simply dragging and hovering the cursor over the desired element. This unconventional behaviour is accomplished on the Web using Flash animations. As expected with most Flash sites, the graphic design is clean and appealingly simple. In terms of content, the site provides some background information regarding the intent of the experiment, as well as a number of prototype "click-less" interface widgets and interactive elements. My sense of the site overall is that it was perhaps developed as a project for a college-level design course. While the writing and overall conceptual premise strike me as lacking depth and sophistication, it's an interesting forum to start thinking a bit about the nature of current GUI design. I suggest you check it out for yourself before reading on.

The Mouse, A Priori


If dontclick.it was intended as a model for new approaches to user interface design, there are a number of key areas where I feel it is ineffective, often falling short of even being useable. Foremost among these is the fact that the design is entirely based around the mouse. This a priori assumption that the mouse is the only option for user input is a profound miscalculation, particularly in the case of the Web. The site designers have neglected the possibility that their users won't be using a mouse exclusively to navigate the site. Indeed, consistent keyboard access is one area where the Web excels in terms of useability, and even the most able users are accustomed to using a blend of keyboard and cursor input. Beyond that, visitors using portable or handheld devices, people with motor impairments, and those of us who already spend too much time making the painfully repetitive movements required by the mouse simply won't be able to use the dontclick.it interface.

The lack of flexibility and adaptability of the design—particularly in its inability to accommodate a variety of input devices—represents a major step backwards and is ultimately a serious barrier to broad usage. In effect, the design is dead in the water from the beginning because of its mouse myopia.

Still, let's go ahead for a moment and try to follow the logic of the site's designers. Let's assume that all of our users are only ever going to use the mouse. Given this, it seems worthwhile to look at what benefits the mouse button provides for to the user, and ask ourselves if the dontclick.it approach offers any improvements.

The mouse click is a very direct and unambiguous control mechanism. Button widgets in most traditional GUIs provide a real-world metaphor to which the user can apply existing expectations about their behaviour. It should be simple; you press a button to activate it. On the other hand, dontclick.it replaces the mouse click with timer-controlled cursor hovering. A user needs to move the mouse over the abstract widget—which may or may not be recognizable as a control—and wait several seconds until the GUI responds to the command. The result of activating a dontclick.it control is a long animation sequence in which the widget shifts out of the way to expose new controls which were previously not visible.

Self-Described Drawbacks


Exploring this behaviour more closely, the dontclick.it site contains a section called the "ButtonLab" which presents a number of proposed click-less interface controls. It allows the user to experiment with the buttons and also describes some benefits and drawbacks for each. I think that this section is the most important aspect of the site, and can provide some insight into the underlying problems of the design. I applaud the site's authors for their ability to provide some considered self-criticism, and I'll use their own words to outline several of the underlying problems.

Drawback #1:
"Chances are high that you unintendedly [sic] activate a button by accidentally moving your mousepointer over it."

Clearly it is very easy to unintentionally trigger a control or selection within dontclick.it. The key here is the fact that the user interface elements are time-based and constantly shift around the screen, moving completely out of the user's control. To make matters worse, an accidental selection in this interface will inevitably involve waiting for a tediously slow animation to complete fully before being able to go back and correct the mistake.

This heavy use of animation is, as far as I can tell, a workaround for the lack of distinct pages or layers in the UI. Every widget exists in a limited, two-dimensional space, and the navigation mechanism is closely coupled to the page content. Unlike traditional scroll bars which are positioned to the side of the content, in this navigation space the cursor regularly gets in the way of actually reading the site's content. Often, an attempt to move the cursor out of the way in order to see the content unobstructed will cause the section to be deactivated, further slowing down the time it takes to use this site.

A case in point here is the survey questions which randomly pop up on the site, requiring a response from the user. The click-less interface makes this into a dangerous kind of modal dialog box, because it can easily be activated accidentally by a user who doesn't move their cursor out of the way quickly enough. My sense is that any survey results they've collected probably reflect this accident-prone design more than any meaningful statistics.

Drawback #2:
"The user has to be initially shown how to activate a button since this kind of navigation is not obvious."

As mentioned above, buttons don't behave like this in the real world. By continuing to use iconic buttons, while actively preventing them from being pressed, the site ignores all of the real-world knowledge a user brings to the situation. Given the complexity of all modern GUIs, why further confound the user with controls that look like what they expect, but don't behave like anything they've ever used before?

Drawback #3:
"This concept of navigation slows down the speed at which content is activated and thus ready for consumption."

Timing is important. Although the dontclick.it experiment is clever and well-decorated, it is tiresome and time-consuming to use. Efficiency of the user is a first principle of user interface design, yet the dontclick.it site requires them to slow their normal rate of productivity down to a glacial pace.

Furthermore, there's no consistency throughout the site in terms of timing conventions. Some UI elements shift very quickly, while others—such as the buttons in the ButtonLab—require painfully slow wipes to activate.

Mouse Movement Recording


The Autopilot section of the site is truly a great idea. It records the first twenty seconds of a previous user's session, providing a document for how new visitors to the site respond to the interface. In nearly each case, the recordings show a user desperately scrubbing the mouse across the screen in an attempt to find familiar Web user interface cues. Watching just how little is accomplished in twenty seconds due to the glacial but eye-catching animations is indeed enlightening.

If the Glove Fitts


It's a curious exercise to see how Fitts' Law is applied (or not) throughout the dontclick.it interface. As a refresher, human interface guru Bruce Tognazzini defines Fitts' Law as "the time to acquire a target is a function of the distance to and size of the target."

Based on this, I like the fact that some of the icons and controls of dontclick.it are large, obvious, and thus easily aquired. But there's a deeper problem that once again relates to the heavy use of animation. Generally, when a dontclick.it control is activated, it causes all of the elements to shift radically across the screen in order to make room for a new set of navigation controls. As a result, the user is constantly chasing widgets across the screen, none of which is ever close to the current position of the cursor. The lack of any screen boundaries within the browser sandbox—a problem inherent with the Web—makes it even more time-consuming to acquire a target.

Asking the Wrong Questions


In the end, I think the problem with the dontclick.it experiment is that the site's authors were asking the wrong questions. As they put it, the core question that the site attempts to answer is "do we miss the click?" Given the simplicity and lack of ambiguity of the mouse, this doesn't strike me as the most insightful of questions in regards to Web user interface design.

With all the exciting developments in standards-based rich Web interfaces—especially AJAX and Google Maps-style interfaces—and the distinct need to improve Web useability and standards overall, why not start with the basics? Start with questions like "am I using the existing standards to their fullest extent?" and "is my site clear, accessible, and useable all visitors?"

Summary


Okay, so this article hasn't so much been about the potential for a click-less interface, nor was it really about the dontclick.it Web site. But it has provided an opportunity to consider—in a rather preliminary way—the nature of the graphical user interface and its relationship to the mouse itself. Although I use a computer with only one mouse button, and feel like one is more than enough, the whole issue seems topical given the popularity of multi-button mice and the recent announcement from Apple of their first such mouse.

As a summary, I'll leave you with my top five concerns with the notion of a click-less interface, at least as implemented by dontclick.it:

  1. The user interface elements move significantly outside of the user's control. Targets shift when you get close to them, requiring slow, large-scale mouse gestures to accomplish basic functions.

  2. Because the navigation mechanism is so closely bound up with the content, the cursor consistently gets in the way of actually reading the content, unlike with a scroll bar. In many cases, an attempt to move the cursor out of the way will have the drastic effect of deactiviting the current section of the site, thus slowing the process of reading down to a frustrating crawl.

  3. Animations are slow to respond to the position of the cursor, and there is no way to easily cancel an operation as you can with a mouse click. This makes it very easy accidentally activate or deactivate a navigational element, requiring the user to wait for the animation before being able to correct the mistake.

  4. Important dialog boxes can be activated accidentally based on the position of the mouse alone, without any input from the user.

  5. Unlike a click-based interface, it's entirely impossible to navigate without the mouse.

Monday, July 04, 2005

Why Code Scents?

Okay, I admit it, Code Scents is kind of a cheap pun. But there is a point behind the oh-so-clever title.

Code Scents is a play on the term "code smell" used originally by Kent Beck on the C2 Wiki to describe the feeling you get when you encounter troublesome code. In my experience, repetitive, overly complex, or clever implementations often stink the most. Following the smell of your code provides a hint of where something may have gone wrong in the system.

The ability to "smell code" is an instinct for refactoring that develops with time and practice, and it takes a certain amount of humility and self-awareness to get good at it. The point here is that good programmers are aware of the quality and context of their code as they are writing it and they strive for simpler, more elegant object designs. It's not about coming up with the perfect solution right away, but rather refactoring the system constantly, allowing it to evolve over time based around the needs of the user.

Despite how code smell has been picked on by critics of extreme programming, I like the concept because it suggests an element of intuition in what is often regarded as a terribly logical occupation. Of course thoughtful problem solving is an essential part of the job, but it's also important for programmers to be aware of the way a design unfolds as it is implemented; to have a sense of the code they're writing. It suggests the importance of simplicity in software development, and emphasizes the role of refactoring in the agile design process.

Word play aside, code sense is skill I'm still nurturing, but the satisfaction of coming up with a succinct metaphor or new design approach for my code always makes the refactoring effort worthwhile.