|
Mastering J2EE Application Development Series
Step 5 of 12: Building More Usable Software
Avoiding an Extreme Makeover
by Jonathan Boutelle and Rashmi Sinha
Bringing usability analysis into the software development process helps J2EE architects avoid the "we can't change that" problem
In the construction business, any remodeling job is a lot easier when the infrastructure has the right elements in place to support the desired changesthe wiring and plumbing meet current building codes and are situated in the proper location for a kitchen remodel or an extra bathroom, for example.
Likewise, making software more usable is a lot easier to do if the core architecture was designed with usability in mind.
Unfortunately, that's usually not the case. Although usability is an important quality of software systems, usability typically isn't addressed until the end of the development process. Usability professionals evaluate users' subjective reactions and use of working systems, and then give developers a laundry list of changessome of which can be easily incorporated into the existing design, but many of which may be prohibitively expensive.
Usability researchers call it the "We can't change that" problem: despite the use of loosely coupled architectures explicitly designed to accommodate shifting requirements, some changes simply can't be made without making fundamentaland expensivechanges to the application's foundation.
In this installment of Mastering J2EE Application Development, we'll describe how architects can be better prepared for the impact of usability requests.
What do J2EE architects need to know about usability?
When it comes to usability, it's the "we can't change that" problem that J2EE architects must know how to avoid, rather than how to create intuitive screens or design user interfaces that customers will respond to emotionally. Usability change requests related to the appearance of the UI alone rarely cause havoc, since even novice J2EE
| "Making software more usable is a lot easier to do if the core architecture was designed with usability in mind."
|
developers know about using the MVC pattern to isolate code for drawing the UIthe Viewfrom the rest of the code (the Model that contains the application data, and the Controller that handles the input processing logic). Workflow- or data-requirement changes to particular screens are also rarely problematic. In general, appearance-oriented changes require some changes to the code, however, they typically won't cause any upheaval in the architecture itself.
For example, MVC frameworks, such as Struts or Spring, let you easily redesign a workflow to extract additional data from the Model, or change screen routingwithout changing a line of code.
On the other hand, change requests that are problematic generally involve the interaction of the View with the Controller and Model, rather than simply the appearance of the system.
Such requests cannot be
accommodated
without major changes to the architecture.
Fortunately, at least some of the usability change requests that can wreak havoc on a system architecture can be predicted by understanding a little more about usability methods. Let's explore a few of them.
Usability heuristics lead to some predictable change requests
If usability change requests were simply arbitrary, architects would have no way to anticipate them. However, this is not the case. J2EE architects can be better prepared for the impact of usability requests by understanding how certain usability feature requests are the direct result of some well-known heuristics, and how implementing those requests will affect the architecture. We begin by describing some usability heuristics, tracing the resultant feature requests, and then discussing how to deal with the architectural impact.
Usability heuristics > Functionality request > Architectural impact and relevant design pattern
This framework links usability to software architecture. While it is not a panacea for all usability issues, it may help protect you from the some of the pain of last minute re-architecting.
Usability experts evaluate systems using several different techniques, two of which are usability testing and heuristic analysis. Most engineers are probably familiar with usability testing, but may not be familiar with heuristic analysis, which is simply using industry-standard "rules of thumb" that have proven over time, on thousands of projects, to be useful in improving usability. Applying these heuristics often leads to some specific (and predictable) feature requests.
A full discussion of all the commonly used heuristics is beyond the scope of this article; however, we examine two heuristics (see Table) to illustrate the link between usability requests and software architecture.
Table 1: Some types of negative system characteristics can be offset by specific usability features
|
System Characteristic | Heuristic | Feature requests |
| High latency | Keep the user informed about how long a task will take | Cancel button | | Progress bar |
| High cost of errors | Help users deal with errors | Undo/redo | | History logging |
In our experience (and also review of related research) these two heuristics often lead to four specific usability feature requests; these feature requests are triggered by specific system characteristics, as discussed below:
 |
Usability features that keep users informed Slow system response can mar the user experience, and requires remedies to help users anticipate response times or cancel actions. Dealing effectively with system response times can motivate functionality requests for:
- Cancel Button: Provide a way of canceling operations that may take more time than the user initially assumed.
- Progress Bar: Provide a progress bar when the system is unresponsive that tells the user how long they will have to wait.
|
 |
Usability features that help users recover from errors Users make errors while using most any system, but support for error recovery is critical if the cost of errors is high (e.g. if one wrong click results in hours of lost work). Two frequent functionality requests related to error recovery that also impact the architecture are:
- Undo / Redo: Enable users to undo and redo the last action.
- History Logging: Track user actions in a log so that the user can look back over what was done previously.
|
Determining that your system will (occasionally) have high latency and determining the cost of errors are both critical to avoiding the "we can't do that" syndrome. Engineering an architecture that can meet usability concerns requires that you take into account development platform considerations, and architectural considerations and relevant design patterns, as discussed below.
Development-platform considerations
In general, both families of usability features have related architectural requirements. For example, if you implement Undo/Redo, you are already most of the way towards implementing History Logging. And if you implement Cancel, you're at least part of the way towards implementing a Progress Bar.
The choice of development platform can helpor hinderyour ability to implement usability features. In general, the more such features (undo/redo, history logging, cancel button, progress bar) you need to support, the more seriously you should consider a Java-based user interface, rather than an HTML-based user interface.
For example, it would be difficult to implement "Cancel" functionality in a vanilla Model 2 Struts-based Web application: once the user submits a request (via stateless http), the Controller takes over and the user has no further control of the UI for the life of that particular command. In addition, although true Undo/Redo functionality is possible in a web application, it is not usually implemented due to user belief that the "back" button performs an undo it doesn't, but non-technical users might not understand that).
On the other hand, an ADF-JClient-based UI remains continuously responsive to user input.
In addition, the technology that you use for your persistence layer can also affect the viability of implementing feature requests such as undo. For example, Object-Relational Mapping products (ORMs), such as Oracle TopLink, can facilitate the roll-back of completed transactions; Oracle Toplink automatically updates data objects when the corresponding records in the database are changed (TopLink's UnitOfWork.revertObject() API).
Architecture considerations and some design patterns
| "Determining that your system will have high latency and determining the cost of errors are both critical to avoiding the we can't do that syndrome."
|
There are well-known design patterns associated with implementing these features (undo, history logging, cancel, progress bar). Below we'll briefly present some of these in a Swing-based UI.
High Response Time Pattern (Progress Bar and Cancel) The key consideration when architecting usability into high latency systems is ensuring that your Controller can always respond to user input. For example, if a user halts a command after he has just issuedsuch as when execution seems to be taking too longthe Controller must be able to gracefully return the system to its prior state.
Functionally, this means starting a new thread for each potentially high-latency command that the View sends to the Controllersomething you won't want to do unless you've determined that high latency is truly a problem.
A benefit of this pattern is that the freed-up Controller thread can calculate the time the high-latency user action will take, and relay that estimate back to the Client code, for display in a status bar. (Estimating the time an action may take is a complicated chunk of functionality in its own right, and should be segregated as a separate object, perhaps informed by real-time system performance statistics).
 |
| Figure 2: Object model of Simple Spreadsheet (no Undo capability), drawn with the Java class modeler in Oracle JDeveloper 10g (10.1.3) Developer Preview . Click here for larger image.
|
High Error Cost Pattern (Undo and History Logging) If errors have a high cost to the user (example: deleting hours of work), then we need to provide the user with recovery and audit mechanisms. Encapsulating communication between View and Controller in Command objects makes it possible to store user actions in temporal order using a Stack, and undo them in reverse order later (this is the familiar "Command" pattern). The Command object is in implementation of the Command interface, which says that a Command knows how to execute() and undo() itself. For an excellent introduction to this pattern, read the documentation for the oracle.ide.ideaddin.Command interface.
A Stack of Command objects can serve as a makeshift History Log. If your users require a permanent history log (for example, for auditing purposes), then we recommend copying the Command objects into a linked list (or simply logging commands, as executed, into a relational database).
Retro-fitting an application
Usability features such as Undo are very expensive to add to an existing application that wasn't designed with that capability in mind. You can do it, but you'll pay a penalty in time and labor, just as you would for a remodeling job that requires new plumbing or major electrical upgrades.
In short, changing the basic way that user commands are sent to the model (enabling them to be undone or cancelled, for example) is a messy business that should be avoided if at all possible. And, as we pointed out earlier, it is possible to avoid, since heuristics analysis reveals the same predictable change requests, time and again. We strongly recommend that usability experts and development management interact early in the projectbefore any code is writtenand make clear decisions about the functionality to be implemented. To illustrate the point, we'll use a simple spreadsheet application to illustrate the cost of adding undo late in the game.
As most software engineers know, implementing Undo is fairly straightforward using the Command pattern Consider the simple spreadsheet application implemented in Swing, shown in Figure 1.
 |
| Figure 1: A Simple Spreadsheet. |
The application provides the minimal functionality for a spreadsheet application, specifically, enabling the user to enter values into cells, edit those values, and delete the contents of a cell.
 |
| Figure 4: Object Model for Simple Spreadsheet (with Undo added later), drawn with the Java class modeler in Oracle JDeveloper 10g (10.1.3) Developer Preview. Click here for larger image.
|
Scenario 1: Usability comes at the end The development team implemented this spreadsheet application without providing undo capability. Oracle JDeveloper 10g visualization of the code for the basic application is shown in Figure 2.
| "We strongly recommend that usability experts and development management interact early in the project."
|
The view calls specific functions on the controller, and the controller, in turn, delegates responsibility for carrying out the appropriate command by calling functions on dedicated helper classes (CellAdderHelper,CellEditorHelper, and CellDeleterHelper). It's the various helper classes that interact with the SpreadsheetModel and make the relevant changes to the SpreadsheetModel class.
The various helper classes all rely on the same parent class (Helper), which comprises common functions that each of the specific helper classes inherits. System response to a user action, such as editing a cell, is simple and straightforward delegation. Figure 3 shows the sequence diagram.
Now that everything is working, the usability professional is called in. She makes some recommendations about the look and feel of the worksheet, and also says that without "Undo" the spreadsheet is not usable.
 |
| Figure 5: Sequence diagram of cell edit / undo for Simple Spreadsheet (with Undo added later), drawn with the Sequence Modeler in Oracle JDeveloper 10.1.3 Developer Preview. Click here for larger image.
|
At this point, the architect has two, equally unappealing alternatives:
- Completely redesign the architecture so that the application can provide Undo functionality. For example, get rid of the Helper classes that the system currently uses and implement the Controller using the Command pattern.
- Leave as much of the existing code alone as possible, but add theUndo functionality as needed throughout the system. For example, implement the Command pattern for discrete Undo commands only, as shown in Figure 4.
This so-called "Half-Command" pattern is lower-risk than the first approach, but at the price of increased system complexity it leads to a convoluted object model in which each new command can result in two additional classes (see Figure 4). (On the other hand, the first approach ("teardown and rebuild") can be high risk (time spent, extra costs, delayed time to market, lost opportunity costs, and so on).
 |
| Figure 6: Object model for UndoableSpreadSheet,drawn with the Java class modeler in Oracle JDeveloper 10g (10.1.3) Developer Preview. Click here for larger image.
|
This architecture will be expensive to maintain (because it will be complicated for new developers to learn, and has a large number of unnecessary classes). Nonetheless, since it can be implemented quickly, with little risk, it may be the only option an architect has in such a situation.
The system's execution of commands (and undoing of commands) is visualized in the sequence diagram below. As you can see, both the Command and the Helper classes access the Model layer, which requires code that can interact with the model be present in both families of classes. The result is significant code bloat and the possibility of coding errors, as well as maintenance issues for the code base.
Scenario 2: When usability is considered early Now let's look at an implementation that was built with Undo as part of the original specification, based on the recommendation of usability experts. Realizing that the cost
of any errors in this system would be high, the system architects anticipated the need for an Undo capability. They designed the system using the classic Command pattern, as shown in Figure 6this should look familiar to most developers.
 |
| Figure 7: Sequence diagram of cell edit / undo for UndoableSpreadsheet, drawn with the Sequence Modeler in Oracle JDeveloper 10.1.3 Developer Preview. Click here for larger image.
|
Obviously, this pattern implementation has fewer classes, and the code is canonicalyou know what it does at first glance.
The sequence diagram of the edit / undo process reveals another advantage: access to the Model is restricted to the Command classes (instead of being parceled out between the Command and Helper classes), which should reduce developer errors as well as the size of the resulting code.
Incorporating Undo into the initial design for the spreadsheet program saved the developers a substantial amount of work, and at the same time resulted in a more elegant, maintainable solution.
Conclusion
By leaving usability considerations out of architectural considerations, software developers assume that if usability problems are discovered, they can be easily fixed. In practice, some usability issues reach too deep into the architecture to be fixed at a reasonable cost. As with any other qualities that you want to architect into your software, usability must be considered up front, at the beginning of the process, and not left until the end.
Features that communicate system state information in real-time or give the user dynamic control over the execution of commands are painful to add in a post-hoc fashion. The framework outlined in this article may prove useful in reducing the number of usability defects that require an extreme makeover.
Jonathan Boutelle (jon@uzanto.com) is a principal at Uzanto Consulting. A software engineer by training, his interests lie at the intersection of technology, business, and customer experience. His current work involves building an innovative rich internet application for remote customer research. He studied Computer Science at Brown University, and has worked as a software engineer for Advanced Visual Systems (a data visualization company) and CommerceOne (a B2B enterprise software company). He writes an occasional article on his blog.
Rashmi Sinha (rashmi@uzanto.com) is a principal at Uzanto Consulting, which specializes in design-focused customer research and usability analysis. She is passionate about making technological products easy to use and has done pioneering work in bringing rigor to the design research process. She has developed a set of methods to understand people's mental models. Her work on Online Recommender Systems has had a wide impact on the design of such systems. For the past two years, Rashmi has also served as an advisor to several companies working to bring technology to the masses in the developing world.
Rashmi has a Ph.D in cognitive psychology. Prior to Uzanto, she was a Lecturer at SIMS, University of California, Berkeley.
[Back to J2EE Series Home Page]
|