|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
TOP THREE LINKS YOU MUST CLICK ON Real-World AJAX Book Preview Real-World AJAX Book Preview: Going Deep into the AJAX User Experience
Real-World AJAX Book Preview: Going Deep into the AJAX User Experience
By: Scott Preston
Apr. 29, 2007 11:00 AM
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.
Going Deep into the AJAX User Experience
Strategy #1 - Define Your Problem Users are very good at telling you what's wrong with something and asking additional questions will often elicit what is really happening. Sometimes it's a bug and sometimes that bug is actually the problem. But most of the time it's symptomatic of something else, like lack of training, a complicated business process, or complicated site navigation. Make sure you don't just try to fix the symptom because you might create a headache for someone else. Second, don't confuse the solution with the problem. I heard just the other day that there was a problem with a component I built. The analyst said it didn't do A, B, or C, which meant to the analyst that the problem was the component. When I asked why it needed to do A, B or C rather than what it did do, I was told A, B, and C would solve problems X, Y, and Z. So I asked, "What if I modified the component to add feature D to solve, X, Y, and Z? "Can you do that?" I was asked. "Yes," I said, "and it's a lot easier to build than reworking A, B, and C." Third, don't take anecdotal evidence as fact. In my ongoing quest to make the best application for each of my clients, I have asked sales staff over the years what the customer didn't like about the application. Sometimes I'd hear they didn't like the number of clicks. Yet, when I spoke with the business analyst, I was told the users asked for a 10-step process, and that they thought the process, was fine. So I'd go back to sales and ask, "I thought you said the users did not like the clicks." Then I'd hear that sales had been talking to the manager, who didn't even use the application. Finally, sometimes you hear your application is too hard to use. Or it may be that your application is perceived to be too diffi cult to use. But until you look at the data and the transactions you really have no way to quantify that perception. Steps to Defining Your Problem
Strategy #2 - Create a Model What I'm talking about is a state machine. A state machine is a series of states and transitions. A state machine diagram (SMD), like Figure 7.1, consists of some circles and some labeled arrows. The arrows are called transitions and the circles are called states. The state machine below represents a pen. You click it once it extends its tip, you click it again and the tip retracts. The states of the pen are in the circles. Pretty simple, right?
Why do state machines help the user experience? Because all user interaction with a computer program is essentially a state machine. Traditional Web applications are especially good at being drawn like state machines because each request is a state transition and each Web page is a state. Creating models with SMDs point you to usability problem areas in an application and give you a countable, quantifiable measure of system usability.
Strategy #3 - Measure the "User Experience" The trick is knowing what a transition is. There are four different kinds of transitions in an application, which I've enumerated below and highlighted in Figure 7.2.
In the example above, you can count the number of areas I have to go to navigate or search. I count three search boxes and three navigation bars. There could also be a few mechanical transitions when moving the scrollbar to find the book I want. There might be two or three artificial transitions because the category that I want to search must be selected before my search results can be displayed. Finally, the number of cognitive transitions is low. The optimized search results are at the top so hopefully I don't have to think much. So whether you're looking at a storyboard (Strategy #6) or a walkthrough (Strategy #7), you have something you can count as you compare. By counting how much a user has to think, click back, or ask questions, you can get a quantitative measure of the system's usability. You can plug those numbers into your favorite spreadsheet program and tally. Just realize that the tally might not give you the whole story. For example, you could have a wizard-like application with a high click count (M) and low think count (C). This might be good for novice users, but won't be for experienced users. On the other hand, configuring via a text file, as in the Unix style, may be the easiest method for experienced users, but not for the novice. That's why it helps to create personas when testing your application.
Strategy #4 - Create Personas Like every business has a target customer, every application has target users. We call these target users personas. For example:
Each of these people will see your application differently, and each of them will have a different user experience. So creating a single application metaphor (a method for using an application while cheaper to write, won't make everyone happy. In the end, your application has a business goal, which could be more productivity, more online sales, more revenue, or more visits. If your user experience doesn't reinforce this goal, it could have dire consequences for your application and your business. To help get an early feel for your application's usability, create a storyboard for your users.
Strategy #5 - Create a Storyboard Creating a storyboard is very similar to creating your model from Strategy #2, except this time you do it with pictures or screenshots rather than circles and arrows.
A good level for storyboarding is to take an overview of your system navigation or process flow, not the ins and outs of data entry or the complicated business rules of an application. Storyboards are good at displaying a high-level overview for your customer and users. It's at a high enough level to get feedback on process and your model, but not detailed enough to get people talking about details and designing pages, which we don't want to do with this method. For a more detailed look at the application's usability, do a walkthrough.
Strategy #6 - Perform an Application Walkthrough This is well before "productization", even before beta. But again, it's a risk-reducing strategy to ensure you're on the right track.
To do a walkthrough:
The best approach is to also compare your application measures to a control. A control is an application or scenario with known usability/user experience scores. You can compare each of your two options against it. So pick something like a Web mail application. This comparison to a known application control will neutralize bias and give you a relative measure.
Strategy #7 - Do a Heuristic Analysis Examples of heuristic analysis points include (from www.useit.com/papers/heuristic/heuristic_list.html):
I've found a good rating system is to use an Excel spreadsheet and rate the issues on a scale of 1-10. Then put versions of your application side-by-side and pick the winner. A tip in doing this analysis is to create concrete items that you can measure for each category. For example, the visibility of system status would measure when things happen in the background, or indicate how far you are within a process. Another example regarding error prevention, the measure could just be the number of errors or back-button clicks the user made.
Strategy #8 - Create a Cheat Sheet Put five or 10 items on the list and distribute it to all your team members. Make them put it in their cubes next to their Dilbert cartoons and pictures of their cat.
Strategy #9 - Go Classic If you hit two or more of the following items, it might be time to go classic.
One area that should definitely stay classic is site navigation.
Strategy #10 - Don't Use AJAX for Navigation When you're moving between pages, don't use JavaScript to take you to pages. Use links instead.
Strategy #11 - Eat Your Own Dog Food One reason I don't like most frameworks is that they take longer to use and figure out than just doing it yourself. There are times when you think you've created the coolest widget or framework. You think it solves all user needs and will vastly improve the user experience. But you never use it outside of testing. In real life, if you don't have time to use your new widget, don't make someone else experiment with it.
Another way to do this is to actually use the applications you build. Be a user for a day or two and actually do his job with the software you built. You'll find it really helpful in how you design and build. Finally, you may find that your requirements makers (managers) don't use the application at all but still think they know what it needs. Sometimes it's good to test them or observe them using the application with their requirements. They often will have a change of heart.
Strategy #12 - Be Consistent If you're upgrading a traditional Web application but only upgrade parts of it, be very careful. By making parts of the application work completely different than other parts, you introduce the unexpected and users don't respond well to that. While you might make new components very clever and nice, the users will have a difficult time transitioning between two metaphors and this increases how much they have to think. Generally, this is not a good idea.
Strategy #13 - Completely Test What You Build If you can't control your browser environment and can't test all browser/platform combinations accessing your site now and in the future, you might want to stick with a traditional Web application. If you have an internal Web application you're designing, try to get commitments from your client to pick a browser version and stick to it. Be aware of security patches that suddenly break your application. If you don't have access to the various hardware or operating systems to test your application, there are plenty of virtual machines out there, where you can install all the major operating systems, including older ones with old browser versions.
Strategy #14 - Break the Back Button (When It Matters)
In my experience, using the back button is fine in Web applications as long as the application doesn't try to resubmit the data twice. So rather than make a blanket statement to "never break the back button", I'd offer slightly different advice: Break the back button (when it matters). When is it okay to break the back button? When the user is using a transaction-based application, like creating, updating, or deleting a record. Let's say your user is at a shopping cart. If she's already confirmed what she wants and has placed an order, you don't want her going back and submitting it again and again, adding the same items two or three times. Here, you want to break the back button. One technique used to break the back button is a token exchange. To understand this process, follow this sequence:
In AJAX use a different route than a hidden field. As an example, in the XmlHttpRequest (XHR) object, add a property called token. In the request, make sure to send the token to the server. When the response is parsed, make sure the token is retrieved.
Strategy #15 - Don't Break the Back Button (When It Matters)
I don't know how often I've heard people say, even about traditional Web applications, "Don't use the back button." Why? Because some developer assumed people will only move forward in their Web application and never want to go back to a previous page. Certain browser mechanisms, like a POST request, give the user nice error messages when they click the back button. When using AJAX, there are two separate methods that don't break the back button. You guessed it. One for Internet Explorer and one is for everybody else. (I haven't tested this with Safari.) The first method works with Firefox 1.5.0.5 under Windows XP SP2. It involves using the location object's hash property. With Firefox, modifying the location.hash creates a history. With Internet Explorer, modifying the loction hash modifies the URL but doesn't add to the history. Listings 7.1-7.4 focus on Firefox. Listings 7.5-7.9 focus on Internet Explorer. Listing 7.1 has a span and a link that invokes the test for the back button. Listing 7.1
<html> Listing 7.2 will create a static page level array of all back button states called bbArray() and a currentIndex holding the current state. The Firefox() function creates a series of events, 200 milliseconds apart to simulate the clicking of items on a page and adding to the history. At the end of this sequence, in three seconds it will start looking to see if the back button was clicked via the startChecking() function. Listing 7.2
<script> The setInner() function in Listing 7.3 increments the innerHTML value by an index. It pushes the text into an array and also sets the location.hash to the index. Changing the location.hash also in Firefox adds to the history. I put this at the bottom of the function. There should be 11 items in the history: the initial page state and the state after 10 hashes have been updated via the for loop above. Now we're ready to start looking for a change in the history. This is done via the startChecking() function and is called after the time-out of three seconds included in the function above. Listing 7.3
function setInner(i) { Every 200 milliseconds the browser will look for a back-button click. It does this by looking at the page's current state and comparing it to what's in its hash property. The page can be in one of the following states, as shown in Listing 7.4.
function checkUrl() { That does it for Firefox. Now for Internet Explorer 6.0 SP2 on Windows XP. As mentioned previously, the hash doesn't add to the history in IE. Listing 7.5 has the same basic layout as before except for the hidden IFRAME. By actually writing new documents to the IFRAME, Internet Explorer adds history just like Firefox did by updating the hash. Listing 7.5 is an example of an HTML page with a function called ie(), a SPAN with an innerHTML that we want to change, and is followed by a hidden IFRAME. The function below will add to the history 10 times, once every 200 milliseconds. I will then tell the browser to start looking for back-button clicks. Listing 7.5
<html> I created one additional function in Listing 7.6 to get the document object from the IFRAME called getIFrameDoc(). Note: This can be done in Firefox too, but it's not possible to access a document object in the cache (history). A permission-denied error is created. Listing 7.6
function getIFrameDoc() { In Listing 7.7, the innerHTML of the ieText span tag is set the same way as it was in Firefox. Some additional coding is needed to update the IFRAME. First, the document object of the IFRAME needs to be retrieved. Then write to the body of the document by opening it, writing to it with the index value, then closing it. This creates the history in Internet Explorer. Now we're ready to start looking for a back button. Listing 7.7
function setInner2(i) { In Listing 7.8 with its checkUrl2, it's almost the same as Listing 7.4, except that rather than looking for the hash, I look at the innerHTML of the doc.body. Finally, I update the hash of the location object so the behavior is similar in IE and Firefox. (Note: While this can be done in Firefox for the current IFRAME, it can't be done for an IFRAME document in its cache. It gives me an "access denied" error.) Listing 7.8
function checkUrl2() { There are frameworks available to encapsulate the functionality for both browsers. You can even do this with what I showed you above, but our focus here is on the user experience not the code. All of this works fine while the user is on the same page, but what happens if he leaves the application by going to Google to search for something and then wants to come back? You'll want to preserve the state of the page but the static JavaScript array has now been released and is gone. The best thing to do here is to serialize the object's holding state with JSON (JavaScript Object Notation). (More information can be found at www.json.org.) Here you call the onUnload event. In Listing 7.9, I put the array in an alert box. You might prefer to make a call to the server and store it in a session or persist it outside of the session. Then if the user returns to the page, he retrieves this session via the session or application by specifying the call in an onLoad event. Listing 7.9
<html> Like the way the Firefox back-button issues were handled, the same method of using the location. hash property for bookmarks and forwarding links can be employed.
Strategy #16 - Allow Bookmarks and Forwarding Links Because most of the state changes occur within a page versus changing from page-to-page, saving a bookmark or forwarding a link has to be accounted and planned for. For this, use the location object's hash property. If the page is simple, just append the hash with a keyword or similar item, i.e., http://www.someserver. com/somepage.php#keyword. Then with an onLoad event get the hash and do something with it. For example, Listing 7.10 creates the ability to bookmark a particular page within an AJAX application. Listing 7.10
<html> The bookmark() function in Listing 7.11 just redirects back to the sample page with a newDate in the query string. This will simulate coming from a bookmark since modifying the hash doesn't involve a new request. Listing 7.11
<script> The next function init() will be called via the onLoad event. Here we check the hash to do something. If you have a state to set or need to make a call to the server to get some data from a previous session, you can do that here. If you want to persist data between sessions, you can retrieve that session and all associated data with it by placing your persistent session identifier in the hash. Listing 7.12
<script> Another option for more complicated pages is to create a QUERY_STRING like a parameter mechanism. So rather than using a ? to delimit the start of a QUERY_STRING, we can use the hash (#). Then we can still separate our key value pairs after it like: http://www.someserver.com/somepage.php?name=value#hash1=value1&hash2=value2 While I don't recommend this for long strings since the URL has a limit, using a few to keep the place and allow for bookmarking and link forwarding should be fine.
Strategy #17 - Keep Users Informed Depending on the nature of your application there are different kinds of notification that could be used. Maybe you want to display an error message. Maybe you are loading some data. Or a user is uploading a file. Maybe to avoid breaking rule #1, which forbids doing the unexpected, you should tell the user exactly what's going on. Use appropriate messages for notifications.
Notifications aren't that complicated. It's best to put them in the same place so users can expect, when they click or do something, that a notification will acknowledge it. Listing 7.13
<html> I'll create a test method for notifications called notify that will create our notification object. You could also create your notifications tag on-the-fly, though I have a static object on the HTML page above. The notification has a time-out property that you can use if you choose. But you'll most likely want to add this notification object to your XHR callback and then call notifyOff() when you're done with your background action. Listing 7.14
<script> What if you don't want ad hoc notifications and want to be consistent for all developers on a team? You will need to create a mechanism so everyone can use the same types of notifications. The first step is to categorize the notifications and put these in your lib.js where you have your application constants. Listing 7.15
<script>
Strategy #18 - Don't Ignore the Browser-Challenged For example, if you're building a site that has to be WCAG 1.0-compliant, your application must act the same way if the JavaScript is turned off. If JavaScript is turned off, there goes your AJAX application. Some of the certifications you can get are levels A, AA, and AAA depending on the requirements your application meets.
These guidelines are seven years old and have now been updated with a version 2.0. Under the right conditions, you're allowed to use JavaScript, but there are restrictions. For example, you can add objects to the DOM via createElement(), but not with document.write(). Speaking practically, I find limiting the JavaScript use paradoxical because the institutions that require it to be compliant also use office suites and other client applications that don't have to meet the same degree of compliance. I was going to start listing the guidelines but I found them too impractical to follow for Web applications, let alone AJAX-enabled applications. If I followed them to the letter, I would end up with a traditional Web application. In the past I've worked with state and local governments that required the application to be WCAGcompliant. Yet when they looked at the application and it didn't have the functionality they wanted, they hated it. I had to tell them, if you want it both ways, you have to pay for it. I've also had occasion to demo an "accessible" version of an application only to find that it wasn't purchased because it looked dull.
Strategy #19 - Notifying the User When Something Has Changed When users make changes to fields in Web applications or when the state of the page changes, it's often useful to make users aware that something has changed. An example of this is the typical email client. Unread mails are usually in bold while the read ones are normal. Note: Avoid using reds and greens. They look the same to the color blind. If you have a form field, you can make changes as well. Look at Listing 7.16. Listing 7.16
<script> Another option is iterating through the DOM and attaching events to each of the fields in the form. Just remember to change the color back to its original state once the data has been submitted.
Strategy #20 - Do Things in the Background to Help the User Sometimes you will want to perform some operation in the background. Perhaps it's a timer checking for changes at certain intervals or maybe it's a user-initiated action. In the case of a user-initiated event, let's use an onchange again. One thing I don't like is having to wait to submit a form especially if I have attachments. To improve the user experience and prevent the user from waiting, we can upload their attachments in the background. Listing 7.17
<p>Background Operations : By combining this with the notification object that we created earlier we have the following example.
Notice that we prevented the user from changing anything while this was happening by disabling the field. We also changed the background color to let the user know that the data had changed. We also added an uploading message in the notifications area of the page. Listing 7.18
<script> Something else along the lines of doing something for the user but not thinking too much for her is to auto-complete some fields.
Strategy #21 - Auto-Complete Fields (If You Can)
Auto-completion involves three steps:
In Listing 7.9, I have a text field and a select field. The text field will capture what the user is typing and the select field will provide an easy way to cycle through possible suggestions for autocompletion. Listing 7.19
<html> The first getKey method is simple. We pass our onKeyDown event to this method and, depending on our browser, we get the number of the key, provided it's not empty. Listing 7.20
function getKey(e) { The first thing I do is to create a static variable for the select position in the suggestion box. I'll keep track of this index as I move up or down. var selectIndex = 0; If the key is up or down, then we'll assume that the user is selecting something from the select box. If enter, then the user has selected the auto-completed item and it's ready to be submitted. Assuming it's not an arrow or enter key, we want to filter our dataset with the items from the textbox. So to do that I pass the value of the textbox to the createList function and then I make the select box viewable. Listing 7.21
function prepop(last,evt) { The set select function is called if the up or down arrow is pressed. Here I just have to set the selectedIndex of the item in the list to either plus or minus 1, and I need to auto-complete the text field with the value of the option field. Listing 7.22
function setSelect(evt) { The create list function, depending on performance considerations, either looks through an array or array of objects, or makes a call to the server to get its data. In this case, I have the getNames function return an array of names with AJAX in it. Listing 7.23
function getNames() { The filter process below is just going to match sub-strings of the textbox with the different options in the select box. So each time I get the list I have to remove all the options from the field and then add them back where they meet my search criteria.
function createList(v) { I only recommend using auto-completion if you can get good performance characteristics from your AJAX application and the patterns of auto-completion are intuitive to the user. Remember, you still have to avoid the pitfalls.
Chapter Summary AJAX User Experience Strategies
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order. LATEST AJAXWORLD RIA STORIES
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||