Tarchitectural Influences on User Interface Design
You can find quite a lot of tarchitectural advice, including my description of layered architectures in Chapter 8, that recommends separating the user interface logic and design from the rest of the underlying system. This is good advice because elements of design such as business logic should be maintained in a manner that allows multiple representations. It is also true that the user interface should have maximum flexibility in presenting data meaningfully for the intended user. Consider an application that monitors processes on a factory floor. One of the monitoring devices may be a thermostat integrated with a specific piece of equipment. The user interface designer should be free to represent the thermostat in whatever way makes most sense: as a gauge, a dial, a simple numerical display, or perhaps something even more creative that hasn't been done before.
That said, my experience shows that in most applications there is no practical way to purely separate the user interface from the rest of the tarchitecture . In fact, as application complexity increases you often have to rely on the idiosyncratic benefits provided by a given kind of user interface, whether it be command line, graphical, haptic, auditory, or any combination thereof.
Areas of Influence
The next sections describe some specific areas where tarchitecture influences user interface design and usability.
Cardinality refers to the number of entities that participate in a given relationship. It is an important element of overall tarchitectural and user interface design because the techniques associated with storing, processing, and representing small numbers of entities vary quite a bit from those associated with storing, processing, and representing large numbers . As cardinality increases, the demand for visual representations of the data and their interactions also increases. Fortunately, the number of tools available for visualizing large data sets continues to increase. make certain you understand how cardinality may affect your user interface.
One of the most important heuristics associated with creating usable systems is providing various kinds of feedback to the user. Feedback assumes a variety of forms, including informational messages, responses to user actions (such as a menu being displayed when selected by the user), progress meters , and so forth. The tarchitecture must be created with an awareness of feedback demands.
Consider the effects of a progress meter, which indicates that the system is processing a request or transaction that is going to take a fairly long time. The portion of the system servicing the request must be designed to allow periodic feedback on its processing status. This can be relatively simple, such as when you issue a request to perform some operation over a finite number of elements and processing each element takes a well-known amount of time. It can also be quite complex, as there are many operations for which you cannot predict in advance the time to complete. Note that this fact also influences the kind of progress meter chosen , another example of how underlying tarchitectural issues influence the design of the user interface.
A special form of feedback concerns early validation, in which the system performs partial validation or near realtime evaluation on every piece of entered data. A trivial example is a data input field for a numeric part number that only accepts numeric characters . A more complex example is an input screen that can partially validate data or an input screen that enables/disables various controls based on previously entered data. Early validation can't be performed on many Web-based systems because the underlying capabilities of HTML and a browser can't support it. More generally , the devices used to access the system do not affect usability in a uniform mannerthe capabilities of every device must be separately understood to ensure you're getting the best usability.
Explicit User Models
One way to take advantage of your understanding of mental models is to create an explicit model of users' understanding in your system and adjust system behavior to it over time. This technique is used in everything from my word processor, which automatically corrects spelling mistakes, to my favorite online bookstore, which recommends books according to my previous purchases.
System architectures and markets often mature together. This is one reason that so many initial system releases have poor workflow support and many mature releases have one or more elements that in some way provide explicit workflow support. As the market and use of the system mature, product development teams can capture best practices and codify them through any number of simple (e.g., wizards, animated help systems) or complex (e.g., scriptable workflow engines) workflow support structures. Workflow support usually builds on top of the understanding we develop of the users' mental models and is in itself a kind of explicit user model.
Many of the operations performed in a system can be thought of as transactionsfor example, simply typing a character into a program that supports undo. Inevitably, transactions, and transaction semantics, affect the user interface and vice versa. Consider a Web site that provides flight information, constructed according to the layered architecture presented in Chapter 8. In extending this system to support a voice-based user interface, you're likely to find that the underlying domain objects and many of the services are perfectly reusable but certain transaction-oriented services are not. This is because transactions are often designed to support a particular kind of user interface capability. For the interface just described, you can create a very large transaction object that captures many fields from the user in a single screen. This is simply not possible in a voice-based interface, where user input must be obtained via small " chunks " because of the complexity of asking the user to correct errors.
Another example is the presentation of information to the user. In a graphical interface, it is easy to provide the user with cues as to how the information is sorted. Thus, your Web-based e-mail program might present all of the messages in your inbox, with simple visual cues as to how they are sorted. In a voice-based interface, you probably won't be able to reuse this logic when presenting information to the user; the underlying logic that obtains these data will also need to change.
How you gather, validate, and respond to user input errors is determined by a complex interaction between your underlying system architecture, your user interface, and the user's tasks . My favorite C++ compiler presents a hyperlinked list of errors in a window; selecting an error takes me to the place in the source code where the compiler thinks the error occurred. This doesn't work for an e-commerce Web site, which must respond to errors with some kind of notification screen (perhaps the fields are in red or preceded by an asterisk). The choices made regarding error presentation will likely affect the underlying tarchitecture.
Internationalization and Localization
In internationalization the underlying tarchitecture supports multiple languages and localized data formats. In localization a given language and style of interaction and/or presentation is specified. The ramifications are substantial and range from formatting monetary values, dates, and numbers to hiring special firms to translate all user information into the supported languages. Operating systems and their platforms provide the infrastructure for determining the user's language. It is up to you to take advantage of this.
It is important to consider everything presented to the user when localizing an application: Error messages, informational messages, dialogs, input/output formats, log files, and even the names of external APIs are all internationalization candidates.
There are several areas in which the development team can make design choices that make internationalization efforts difficult. Some of the more common mistakes include using fixed-size dialogs and dialog components , embedding information displayed to users within source code, and failing to use the services provided by modern operating systems to select the property localization information at run time.
Internationalization efforts include converting fixed-size dialog and dialog components to handle variable width text, allowing for text that flows right-to-left as well as left-to-right , and multi-byte or double-byte character sets. Information displayed to the user should never be embedded within the source code, but should instead be referenced by an identifier that is passed to a component that converts the identifier to the appropriate output at runtime, based on appropriate localization settings.This component can be used for everything from the information displayed in error dialogs to that written to log files (localizing log files can have dramatic effects in customer satisfaction). The foundation of all of these techniques is proper use of operating system facilities to select localization information and settings at runtime. This is an ongoing area of improvement, and tarchitects should routinely monitor operating system upgrades for internationalization/localization improvements.
Because of the far reaching impacts of internationalization and localization, marketects should specify their target languages very early in the development process as well as those languages likely to be used down the road. If in doubt, assume the possibility of Far Eastern and Right-to-Left languages, and design the architecture accordingly .
Usability in many kinds of systems can be substantially improved when requests that may take a long time to process or consume many resources can be cancelled. Users feel more in control, and overall system performance can improve as the system is not engaged in unnecessary work. The option to cancel an operation can also provide excellent hooks to system administrators to tune system performance, especially in multi-user systems.
If you're building a single-user, desktop application, creating a tarchitecture that can cancel requests can be pretty easy. If you're building any system that shares state with other systems or users, is based on a client/server architecture, or relies on cascading the request through multiple components, this can be hard or impossible . Creating cancelable requests in these systems requires careful tarchitectural design. When a client initiates a cancelable request, it must be given some kind of identifier to reference that request in the future. The server must be extended to associate request identifiers with requests, ensure that requests can be terminated , and properly recover system resources. This can be very challenging, especially when requests are distributed among third-party, in-licensed components.
To illustrate , one system I worked on allowed users to initiate requests that invoked the services of two in-licensed components: a database from one vendor and a search engine from another. Coordinating the cancellation process between these technology components took a fair amount of programming, but the results were worth it.
I am not differentiating between traditional kinds of enterprise class systems or those based on Web services and service oriented architectures. In fact, I'm concerned that many of the published approaches to creating Web services and service oriented architectures do not address request cancellation. Suppose, for example, that a Web service takes a long time to compute a result or consumes a large amount of resources doing so. It should be possible to cancel these requests once they have been initiated, for all of the reasons described above. Web services don't change this aspect of usability, and it is important to understand that request-cancellation semantics must be an early consideration in tarchitectural design.
Each request should be assessed to determine if cancellation makes sense. Small requests that can be quickly computed do not warrant the overhead associated with cancellation.
In addition to canceling requests, usability is generally improved when a user can undo the result of a request. Like cancellation, this can be pretty easy to implement in the domain of single-user, desktop-oriented software. In the domain of enterprise-class software, when system state is shared among technology components and users, the concept of undoing a request may not make sense or may be impossible.
Suppose, for example, you've created a system that allows users to collaboratively work on documents stored into folders on a shared server. At time t , Pradeep adds a document. At time t 1 , Sally deletes it. While Pradeep may think that he can undo the operation, in reality he cannot. This example can be extended to a large number of scenarios and can occur whenever two or more entities share state.
Sophisticated tarchitectural design, especially in the domain of transaction management as well as the use of publishsubscribe protocols, can enable you to provide substantial undo capabilities, even in the presence of a shared state. For example, in the previous example the system could keep track of the number of entities that have access to the shared folder. If a single entity is using the folder then single-user semantics, including such things as undo, could apply. Transactions can be extended to attempt an undo operation on behalf of a user; chances are probably good that it will succeed. Finally, rich user interfaces that maintain close correlation with the persistent state of the application can provide users with the information they need to determine if undo makes sense.
Certain classes of business transactions cannot be cancelled or undone. For example, suppose your employer incorrectly calculates your payroll and automatically deposits the amount in your account. Chances are good that the money will be in your bank account before you receive the payroll stub and notify your manager of the error. The operation can't be undone or canceled . In this scenario the system must be extended through the use of compensating transactions. I've included compensating transactions in the section of usability because most business systems that fail to include them are very hard to use. You can't escape the effects of a compensating transaction, and adding them early in the design substantially improves usability.
Systems that require a session with another system or the user often have a variety of timeouts. Choosing the wrong value can lower usability, consume unnecessary system resources, and ultimately require the user to work more to accomplish her desired tasks. This is one area where sensibly chosen defaults can really help your application be perceived as truly usable. Default values are not enough, and session- related parameters must be under the control of the system administrators.
Many architectures use networks, but they don't have the luxury of an always-on connection, speed guarantees , or notification of a change in these states. Consider the context of the user as you address network issues. Chances are good that their context will differ from yoursplan accordingly.
All systems have one or more resources that are shared. For example, I've worked with searching systems that take over all available processors in a multiprocessor system, leaving none for other work. A better design would enable the system administrator to tune the number of processors the search service consumes. Make certain that your system's concept of usability extends to other system's.
Systems can fail in a variety of ways. Tarchitectural choices make certain kinds of failures more or less likely. Once a failure occurs, how your system handles it directly affects usability. Ideally, your system handles and recovers from the failure in a reasonable manner, such as when your printer driver attempts to retry your print job. Failure conditions also are fodder for enhancing system design, especially when you can convert previously unhandled failure conditions into automatically handled failure conditions that do not disrupt the user.
Even if you handle as many failure conditions as possible, you will likely have to alert the user to some of those associated with your system. You can inform users of any of the following: potential negative effects of the failure and their magnitude, potential and/or recommended recovery procedures, and future preventative actions.