- •preface
- •acknowledgments
- •about this book
- •Who should read this book?
- •Roadmap
- •Code conventions
- •Code downloads
- •Author Online
- •About the title
- •About the cover illustration
- •Rethinking the web application
- •A new design for the Web
- •1.1 Why Ajax rich clients?
- •1.1.1 Comparing the user experiences
- •1.1.2 Network latency
- •1.1.3 Asynchronous interactions
- •1.1.4 Sovereign and transient usage patterns
- •1.1.5 Unlearning the Web
- •1.2 The four defining principles of Ajax
- •1.2.1 The browser hosts an application, not content
- •1.2.2 The server delivers data, not content
- •1.2.3 User interaction with the application can be fluid and continuous
- •1.2.4 This is real coding and requires discipline
- •1.3 Ajax rich clients in the real world
- •1.3.1 Surveying the field
- •1.3.2 Google Maps
- •1.4 Alternatives to Ajax
- •1.4.2 Java Web Start and related technologies
- •1.5 Summary
- •1.6 Resources
- •First steps with Ajax
- •2.1 The key elements of Ajax
- •2.2 Orchestrating the user experience with JavaScript
- •2.3 Defining look and feel using CSS
- •2.3.1 CSS selectors
- •2.3.2 CSS style properties
- •2.3.3 A simple CSS example
- •2.4 Organizing the view using the DOM
- •2.4.1 Working with the DOM using JavaScript
- •2.4.2 Finding a DOM node
- •2.4.3 Creating a DOM node
- •2.4.4 Adding styles to your document
- •2.4.5 A shortcut: Using the innerHTML property
- •2.5 Loading data asynchronously using XML technologies
- •2.5.1 IFrames
- •2.5.2 XmlDocument and XMLHttpRequest objects
- •2.5.3 Sending a request to the server
- •2.5.4 Using callback functions to monitor the request
- •2.5.5 The full lifecycle
- •2.6 What sets Ajax apart
- •2.7 Summary
- •2.8 Resources
- •Introducing order to Ajax
- •3.1 Order out of chaos
- •3.1.1 Patterns: creating a common vocabulary
- •3.1.2 Refactoring and Ajax
- •3.1.3 Keeping a sense of proportion
- •3.1.4 Refactoring in action
- •3.2 Some small refactoring case studies
- •3.2.2 Managing event handlers: Observer pattern
- •3.2.3 Reusing user action handlers: Command pattern
- •3.2.4 Keeping only one reference to a resource: Singleton pattern
- •3.3 Model-View-Controller
- •3.4 Web server MVC
- •3.4.1 The Ajax web server tier without patterns
- •3.4.2 Refactoring the domain model
- •3.4.3 Separating content from presentation
- •3.5 Third-party libraries and frameworks
- •3.5.2 Widgets and widget suites
- •3.5.3 Application frameworks
- •3.6 Summary
- •3.7 Resources
- •Core techniques
- •The page as an application
- •4.1 A different kind of MVC
- •4.1.1 Repeating the pattern at different scales
- •4.1.2 Applying MVC in the browser
- •4.2 The View in an Ajax application
- •4.2.1 Keeping the logic out of the View
- •4.2.2 Keeping the View out of the logic
- •4.3 The Controller in an Ajax application
- •4.3.1 Classic JavaScript event handlers
- •4.3.2 The W3C event model
- •4.3.3 Implementing a flexible event model in JavaScript
- •4.4 Models in an Ajax application
- •4.4.1 Using JavaScript to model the business domain
- •4.4.2 Interacting with the server
- •4.5 Generating the View from the Model
- •4.5.1 Reflecting on a JavaScript object
- •4.5.2 Dealing with arrays and objects
- •4.5.3 Adding a Controller
- •4.6 Summary
- •4.7 Resources
- •The role of the server
- •5.1 Working with the server side
- •5.2 Coding the server side
- •5.2.1 Popular implementation languages
- •5.3 The big picture: common server-side designs
- •5.3.1 Naive web server coding without a framework
- •5.3.2 Working with Model2 workflow frameworks
- •5.4 The details: exchanging data
- •5.4.2 Introducing the planet browser example
- •5.5 Writing to the server
- •5.5.1 Using HTML forms
- •5.5.2 Using the XMLHttpRequest object
- •5.5.3 Managing user updates effectively
- •5.6 Summary
- •5.7 Resources
- •Professional Ajax
- •The user experience
- •6.1 Getting it right: building a quality application
- •6.1.1 Responsiveness
- •6.1.2 Robustness
- •6.1.3 Consistency
- •6.1.4 Simplicity
- •6.1.5 Making it work
- •6.2 Keeping the user informed
- •6.2.1 Handling responses to our own requests
- •6.2.2 Handling updates from other users
- •6.3 Designing a notification system for Ajax
- •6.3.1 Modeling notifications
- •6.3.2 Defining user interface requirements
- •6.4 Implementing a notification framework
- •6.4.1 Rendering status bar icons
- •6.4.2 Rendering detailed notifications
- •6.4.3 Putting the pieces together
- •6.5 Using the framework with network requests
- •6.6 Indicating freshness of data
- •6.6.1 Defining a simple highlighting style
- •6.6.2 Highlighting with the Scriptaculous Effects library
- •6.7 Summary
- •6.8 Resources
- •Security and Ajax
- •7.1 JavaScript and browser security
- •7.1.1 Introducing the “server of origin” policy
- •7.1.2 Considerations for Ajax
- •7.1.3 Problems with subdomains
- •7.2 Communicating with remote services
- •7.2.1 Proxying remote services
- •7.2.2 Working with web services
- •7.3 Protecting confidential data
- •7.3.1 The man in the middle
- •7.3.2 Using secure HTTP
- •7.3.3 Encrypting data over plain HTTP using JavaScript
- •7.4 Policing access to Ajax data streams
- •7.4.1 Designing a secure web tier
- •7.4.2 Restricting access to web data
- •7.5 Summary
- •7.6 Resources
- •Performance
- •8.1 What is performance?
- •8.2 JavaScript execution speed
- •8.2.1 Timing your application the hard way
- •8.2.2 Using the Venkman profiler
- •8.2.3 Optimizing execution speed for Ajax
- •8.3 JavaScript memory footprint
- •8.3.1 Avoiding memory leaks
- •8.3.2 Special considerations for Ajax
- •8.4 Designing for performance
- •8.4.1 Measuring memory footprint
- •8.4.2 A simple example
- •8.5 Summary
- •8.6 Resources
- •Ajax by example
- •Dynamic double combo
- •9.1 A double-combo script
- •9.2 The client-side architecture
- •9.2.1 Designing the form
- •9.2.2 Designing the client/server interactions
- •9.3 Implementing the server: VB .NET
- •9.3.1 Defining the XML response format
- •9.4 Presenting the results
- •9.4.1 Navigating the XML document
- •9.4.2 Applying Cascading Style Sheets
- •9.5 Advanced issues
- •9.5.2 Moving from a double combo to a triple combo
- •9.6 Refactoring
- •9.6.1 New and improved net.ContentLoader
- •9.7 Summary
- •Type-ahead suggest
- •10.1 Examining type-ahead applications
- •10.1.2 Google Suggest
- •10.2.1 The server and the database
- •10.3 The client-side framework
- •10.3.1 The HTML
- •10.3.2 The JavaScript
- •10.3.3 Accessing the server
- •10.5 Refactoring
- •10.5.1 Day 1: developing the TextSuggest component game plan
- •10.5.3 Day 3: Ajax enabled
- •10.5.4 Day 4: handling events
- •10.5.6 Refactor debriefing
- •10.6 Summary
- •11.1 The evolving portal
- •11.1.1 The classic portal
- •11.1.2 The rich user interface portal
- •11.2 The Ajax portal architecture using Java
- •11.3 The Ajax login
- •11.3.1 The user table
- •11.4 Implementing DHTML windows
- •11.4.1 The portal windows database
- •11.4.3 Adding the JS external library
- •11.5 Adding Ajax autosave functionality
- •11.5.1 Adapting the library
- •11.5.2 Autosaving the information to the database
- •11.6 Refactoring
- •11.6.1 Defining the constructor
- •11.6.2 Adapting the AjaxWindows.js library
- •11.6.3 Specifying the portal commands
- •11.6.4 Performing the Ajax processing
- •11.6.5 Refactoring debrief
- •11.7 Summary
- •Live search using XSLT
- •12.1 Understanding the search techniques
- •12.1.1 Looking at the classic search
- •12.1.3 Examining a live search with Ajax and XSLT
- •12.1.4 Sending the results back to the client
- •12.2 The client-side code
- •12.2.1 Setting up the client
- •12.2.2 Initiating the process
- •12.3 The server-side code: PHP
- •12.3.1 Building the XML document
- •12.3.2 Building the XSLT document
- •12.4 Combining the XSLT and XML documents
- •12.4.1 Working with Microsoft Internet Explorer
- •12.4.2 Working with Mozilla
- •12.5 Completing the search
- •12.5.1 Applying a Cascading Style Sheet
- •12.5.2 Improving the search
- •12.5.3 Deciding to use XSLT
- •12.5.4 Overcoming the Ajax bookmark pitfall
- •12.6 Refactoring
- •12.6.1 An XSLTHelper
- •12.6.2 A live search component
- •12.6.3 Refactoring debriefing
- •12.7 Summary
- •Building stand-alone applications with Ajax
- •13.1 Reading information from the outside world
- •13.1.1 Discovering XML feeds
- •13.1.2 Examining the RSS structure
- •13.2 Creating the rich user interface
- •13.2.1 The process
- •13.2.3 Compliant CSS formatting
- •13.3 Loading the RSS feeds
- •13.3.1 Global scope
- •13.3.2 Ajax preloading functionality
- •13.4 Adding a rich transition effect
- •13.4.2 Implementing the fading transition
- •13.4.3 Integrating JavaScript timers
- •13.5 Additional functionality
- •13.5.1 Inserting additional feeds
- •13.5.2 Integrating the skipping and pausing functionality
- •13.6 Avoiding the project’s restrictions
- •13.6.1 Overcoming Mozilla’s security restriction
- •13.6.2 Changing the application scope
- •13.7 Refactoring
- •13.7.1 RSS reader Model
- •13.7.2 RSS reader view
- •13.7.3 RSS reader Controller
- •13.7.4 Refactoring debrief
- •13.8 Summary
- •The Ajax craftsperson’s toolkit
- •A.1 Working smarter with the right toolset
- •A.1.1 Acquiring tools that fit
- •A.1.2 Building your own tools
- •A.1.3 Maintaining your toolkit
- •A.2 Editors and IDEs
- •A.2.1 What to look for in a code editor
- •A.2.2 Current offerings
- •A.3 Debuggers
- •A.3.1 Why we use a debugger
- •A.3.2 JavaScript debuggers
- •A.3.3 HTTP debuggers
- •A.3.4 Building your own cross-browser output console
- •A.4 DOM inspectors
- •A.4.1 Using the Mozilla DOM Inspector
- •A.4.2 DOM inspectors for Internet Explorer
- •A.4.3 The Safari DOM Inspector for Mac OS X
- •A.5 Installing Firefox extensions
- •A.6 Resources
- •JavaScript for object-oriented programmers
- •B.1 JavaScript is not Java
- •B.2 Objects in JavaScript
- •B.2.1 Building ad hoc objects
- •B.2.2 Constructor functions, classes, and prototypes
- •B.2.3 Extending built-in classes
- •B.2.4 Inheritance of prototypes
- •B.2.5 Reflecting on JavaScript objects
- •B.2.6 Interfaces and duck typing
- •B.3 Methods and functions
- •B.3.1 Functions as first-class citizens
- •B.3.2 Attaching functions to objects
- •B.3.3 Borrowing functions from other objects
- •B.3.4 Ajax event handling and function contexts
- •B.3.5 Closures in JavaScript
- •B.4 Conclusions
- •B.5 Resources
- •Ajax frameworks and libraries
- •Accesskey Underlining Library
- •ActiveWidgets
- •Ajax JavaServer Faces Framework
- •Ajax JSP Tag Library
- •Ajax.NET
- •AjaxAC
- •AjaxAspects
- •AjaxCaller
- •AjaxFaces
- •BackBase
- •Behaviour
- •Bindows
- •BlueShoes
- •CakePHP
- •CL-Ajax
- •ComfortASP.NET
- •Coolest DHTML Calendar
- •Dojo
- •DWR (Direct Web Remoting)
- •Echo 2
- •FCKEditor
- •Flash JavaScript Integration Kit
- •Google AjaxSLT
- •Guise
- •HTMLHttpRequest
- •Interactive Website Framework
- •Jackbe
- •JPSpan
- •jsolait
- •JSON
- •JSRS (JavaScript Remote Scripting)
- •LibXMLHttpRequest
- •Mochikit
- •netWindows
- •Oddpost
- •OpenRico
- •Pragmatic Objects
- •Prototype
- •Qooxdoo
- •RSLite
- •Ruby on Rails
- •Sack
- •SAJAX
- •Sarissa
- •Scriptaculous
- •SWATO…
- •Tibet
- •TinyMCE
- •TrimPath Templates
- •Walter Zorn’s DHTML Libraries
- •WebORB for .NET
- •WebORB for Java
- •XAJAX
- •x-Desktop
- •XHConn
- •index
- •Symbols
- •Numerics
212CHAPTER 6
The user experience
In chapter 1, we discussed usability, the keystone to any software application. No matter how well organized your codebase and how clever the technical merits of your application, if the usability stinks, you leave a bad association in the user’s mind. This can be grossly unfair, but it’s a fact of life. More people recognize Albert Einstein for his hangdog looks and wild hair than understand what he was trying to say about the nature of space-time. First impressions—and attention to detail—matters.
In chapters 2 to 5, we introduced a lot of cool technology and did some clever things with Ajax. The focus on organization throughout the latter part of this journey has enabled us to be flexible and highly adaptive about how we do these things. However, our examples have been rather rough around the edges, and rightly so while we focused on the cleverness at hand, but now we need to step back and assess what we have done in terms of creating something that people will actually want to use, possibly for several hours a day. The topics presented in this chapter will go a long way toward helping you get your Ajax application ready and presentable for the real world.
One of the biggest things that you can do to make your users feel comfortable with your application is to keep them informed about background events in a discrete and consistent fashion. They aren’t the be-all and end-all of usability, but we will focus on them in this chapter in order to show how an in-depth, consistent treatment benefits the application as a whole. Most Ajax applications will want to notify the user at some point too, so we hope you’ll find the finished components useful in your own projects as well.
We develop several solutions in this chapter for letting the users know what is going on, without getting in the way of their workflow. Before we go into these specifics, though, let’s take a quick look at what we mean by quality and how to get there.
6.1 Getting it right: building a quality application
Usability is an especially hot topic for Ajax because web app users can be an extremely fickle bunch. The downside of being able to download and run your app with zero effort is that the users have invested no time and effort in it when they start to use the application and will be willing to throw it away and move on to the next of the 8 billion web pages that Google can point them to. To complicate matters further, with Ajax we are seeing the convergence of two different usability traditions, namely the desktop application and the web page. Getting
Getting it right: building a quality application |
213 |
|
|
the mixture right can be quite a challenge, and failing to get it right can consign your hard work to obscurity.
In chapter 1, we looked at usability from the users’ point of view. What do they want in an application? And what are they willing to put up with? Let’s turn the question around now and ask what qualities we need in our code to meet the goal of usability. With this as a starting point, we can figure out what we can do in practical terms to make our application work. The following sections detail a number of key features that add quality to your application.
6.1.1Responsiveness
The most basic frustration that a computer user can suffer from is to have workflow interrupted while the computer struggles to catch up with him. Basic design mistakes, such as locking up the entire user interface while writing some lengthy configuration file to disk, can cause the user to lose track of what he is doing and force him to make the mental leap between the domain model in which he is engaged to the harsh reality of computer hardware.
When looking at responsiveness, it can be important to understand your target audience and its typical system setups. In the case of writing a configuration file, the speed may be acceptable on the developer’s high-speed 7200-RPM SATA disk drive on the local workstation, but the customer writing the file to a congested network share or a USB thumb drive may have a different experience. In the specific case of web app development, a similar mistake is often made in only testing the application running over the loopback interface, that is, the web server running on the same development machine as the web browser. This doesn’t give a useful evaluation of network latency issues, and all web apps ought to be either tested over a real LAN or WAN or simulated using a traffic-shaping tool.
Beyond network issues, the performance of the client code can make a huge difference to responsiveness. Performance is a big issue, so we’ll defer a closer look at it to chapter 7.
6.1.2Robustness
An application is robust if it can withstand the usual conditions encountered at a busy workstation. How does it cope with a temporary network outage? If a badly behaved program hogs the CPU for five minutes, will your application still work afterwards? At one recent project that I was involved in, we would test our application’s robustness by pounding randomly on the keyboard for 10 seconds or so, and by “scribbling” the mouse across the page while clicking it. A crude sort of test—but effective—and quite good fun!
214CHAPTER 6
The user experience
What can such a test reveal? For one thing, it can highlight inefficiencies in event-handler code. Keypresses, mouse moves, and the like need to return quickly, since they are apt to be called very frequently. Further, they can reveal unintentional dependencies between components. A particular condition may arise in a GUI, for example, where a modal dialog is blocking access to the main application, but an open menu item is blocking access to the modal dialog. If such a situation depends on precise timing in the opening of the dialog and the menu, it might take a single user two months of daily work to discover it. Once released to an audience of several thousand, however, it might start showing up within hours and be extremely hard to reproduce from field reports. Identifying the problem up front, and correcting it, increases the overall robustness of the application.
There is more to robustness than randomly thumping the keyboard. Just as valuable is the process of watching someone other than the developer trying to use the application. In the case of a complete newcomer, this can provide helpful information on the overall usability design, but it is also useful to let someone closely acquainted with the domain knowledge, even the product, test-drive a new bit of functionality. When the person who wrote the code runs the program, she can “see” the code behind it and may subconsciously avoid specific combinations of actions or particular actions in specific contexts. The end user won’t have this insider knowledge, of course, and neither will the developer sitting next to you (unless you do pair programming). Getting someone else to informally run through your app workflow can help to build up robustness early on.
6.1.3Consistency
As we already noted, the usability patterns of Ajax are still evolving from a mishmash of desktop application and web browser conventions. Some Ajax toolkits, such as Bindows, qooxdoo, and Backbase, even present widget sets deliberately styled to look like desktop application buttons, trees, and tables.
The right answer to this conundrum is still being worked out by webmasters, usability gurus, and everyday users of the Web as it continues to evolve. In the meantime, the best advice available is to keep things consistent. If one part of your application uses web-style single clicks to launch pop-up windows, and another part requires double-clicks on similar-looking icons, your user will quickly become confused. And if you must have a talking pig that guides your users around the site, make sure that it doesn’t suddenly change its accent, costume, or hairstyle halfway through!
Getting it right: building a quality application |
215 |
|
|
From the point of view of your codebase, consistency and reuse go hand in hand. If you cut and paste functionality from one location to another, and then respond to a change request in three copies of the button-rendering code but miss a fourth, the consistency of your interface will erode over time. If there is only one copy of the button-rendering code that everyone uses, then the consistency of your application is likely to remain high. This applies not only to visual UI behavior but also to less-visible parts of the interface, such as network timeouts and responses to bad data.
6.1.4Simplicity
Finally, we need to stress the importance of simplicity. Ajax allows you to do a number of wild and creative things, the likes of which have never been seen in a web page before. Some of these things have never been seen because the necessary technology is only just arriving on the scene. In other cases, there are good reasons for not implementing a feature. Spring-loaded menus that bounce onto the screen and gradually dampen their oscillations may be great fun to code and great fun for a short-term user dropping by for five minutes to let off steam. If the user is going to use the application for several hours a day, though, she is less likely to appreciate the fun by the day’s end.
It is always worth asking whether a new feature will actually improve the end experience. In many cases with Ajax, the answer will be yes, and the developer can concentrate on coding features that will be genuinely beneficial.
6.1.5Making it work
It’s probably the case that your code doesn’t exhibit all the features we just mentioned. Mine certainly doesn’t. These are merely ideals that we’ve presented. Making the effort to move toward these ideals can pay big dividends when it comes to maintaining your codebase in the future, and refactoring existing code can introduce these qualities as you go along. Choosing where to concentrate the effort is something of a black art, and the only way to get good at it is by practicing. If you’re new to refactoring, start with something small and gradually work outward. Remember, refactoring is an incremental process, and you can add quality to your code without pulling it apart and leaving bits on the floor for weeks on end.
In the remainder of this chapter, we’ll look at some specific features that you can build into Ajax applications. A large part of the chapter focuses on notification frameworks, which are ways of keeping the user informed while background processes such as calculations or network requests take place. By providing the user