- We design and build extraordinary applications for companies looking to make the next great idea a reality.
- learn more
Dying to see the new Gmail’s back-button support in action
Even though it's on a slow rollout and has reached only a handful of users, Gmail's new UI has already earned tons of coverage. The new Gmail boasts a fast new JavaScript architecture, an improved contact manager and a host of interface tweaks, all of which I'm dying to see and use. But the feature that excites me the most is back-button support.
From the Google Operating System blog (emphasis mine):
Gmail has a new architecture that improves the performance and the usability. Now you can use the back button in your browser and bookmark URLs from different Gmail views because the URLs change when you go to a different section. The messages are prefetched when Gmail loads so you don't have to wait too much until a message is displayed.
With all the work I'm doing on Really Simple History, I'm excited to see exactly what kind of back-button support the new Gmail offers. If I use the "newer" and "older" links to navigate through 10 messages, will I be able to use the back button to cycle back through them? Or will only the major views of the page (Inbox, Starred, All Mail, etc.) get stored in the browser's history? I'm also interested as to why only IE7 and Firefox users will see the new interface. What's holding up Safari support? (For that matter, what's been holding up official Opera support all these years?)
If you're one of the lucky few who's already gotten to see the upgrade, please tell us all about it in the comments - especially your experience with the back button.
In the meantime, here's a round-up of posts about the upgrade:
Technorati Tags
Topics: Google, Javascript, Really Simple History
Aptana 1.0 Released
Since Aptana, the slick IDE/Eclipse plugin came on the scene in 2006, it has been making steady progress, adding new features on an almost weekly basis. Now they have finally released 1.0. What's new in 1.0?
- CSS Preview
- HTML, CSS, and JavaScript Formatting
- Code drag and drop
- Visual ScriptDoc Explorer
- Enhanced Dynamic Help System
Two of the major changes? First, they have changed the name to Aptana Studio. Second, they have done that all too familiar split between "Community" and "Professional" editions. Right now it looks like your $99 intro price ($199 later) buys you a few more things beyond the free community edition:
- JSON Editor
- Internet Explorer Debugging
- Remote Project Creation
- FTPS and SFTP Support
- Reporting Engine
You also get priority support and access to prerelease and nightly builds. These dual edition splits have worked in the past, as long as the "free" edition was not too far behind the "pro" one. It is a delicate balance, making the pro edition tempting enough without giving the free edition's users the feeling that they are getting screwed.
Technorati Tags: ajax, ide, aptana
Topics: Announcement, IDE
Really Simple History 0.6 countdown: Bug fixes, SVN repo, mailing list, downloads, more
Lots more news on Really Simple History, the open-source Ajax bookmarking library I'm now spearheading:
- SVN - RHS now has a Subversion repository. The version trail starts with the 0.6 beta. Since its release, I've been committing bug fixes and refinements as I get them tested. Feel free to check out a read-only copy if you're already bored with the beta.
- Mailing list: I've also started a Google Group for the project. In the future, that will become the primary means of communication for RHS, and I'll get back to other subjects here on Agile Ajax.
- Bug fix: for/in loops - It's universally acknowledged that they're considered harmful, but I unthinkingly added one to the codebase just before zipping up and publishing the 0.6 release. That's now remedied in SVN.
- Bug fix: Safari - The initial 0.6 beta also had a major shortcoming in its Safari 2/Mac implementation. Bookmarking worked great as long as you didn't navigate away from your RSH-enabled app and then come back. If you did, goodbye, history. It turns out that the history.length hack fails in these circumstances because the browser resets the value each time the page loads. My solution was to add yet another hidden form field and store the initial history.length value there the first time the app loads during a session. Upon subsequent loads, I grab the value from this field instead of from history.length. Hacks upon hacks upon hacks, but it works.
- Enhancement: test page - I've continued to refine the test page. It's now got a single logging console instead of three separate ones, plus easier-to-read log messages and more user-friendly controls.
- Download archive - I've created a bunch of for-posterity-only downloads of Brad Neuberg's original versions 0.1 through 0.4. It seemed a little silly to create a retroactive SVN trail for them.
As of this writing, 225+ people have downloaded 0.6 beta. That's in addition to the 2150+ people who have downloaded the stable 0.4 release in just the six weeks that it's been hosted at Google Code. It's really hitting me how many people actually use this thing, which spurred me to spend my weekend on the tasks listed above. I'm working hard to address the following additional issues before putting out a non-beta release:
- Bug fix: Safari infinite loading bug - I want to get rid of the stupid, eternally spinning disc on my RSH Safari tab. The fix is out there in the world; I just need to implement it.
- Bug fix: Opera history dies when you navigate away and back - I licked this in Safari, so now on to Opera.
- Bug fix: IE user-typed history entries - RSH 0.4 handled these properly, but I broke something in 0.6. It's a corner case, but I'd hate to undo Brad's hard work to handle it.
- Enhancement: window.onunload - RSH has always clobbered previously defined onunload handlers. In this era of memory leaks and the onunload events that help plug them, I want to handle this more gracefully.
- Enhancement: JSON bridging - The standard JSON library I'm shipping with RSH doesn't play well with Prototype. I need to provide a better mechanism than brute force for individual users to override these methods with their own JSON serializer and stringifier.
- Enhancement: Graceful failure - I want to add better user-agent detection and set a global flag to just turn RSH off for those user-agents that aren't supported. Right now, for instance, the library thinks Safari works, period, when really only Safari 2/Mac works perfectly.
I'm pretty confident I can get most of this committed this week. If you're an RSH user, please let me know if there's anything I'm overlooking.
Technorati Tags
Topics: Ajax Frameworks, Really Simple History
Ajax Intervention: Comcast.com
Welcome to Ajax Intervention, in which we dissect how major websites misuse, or fail to use, Ajax to improve their user experience.
Up this time: Comcast.com, which, despite an extremely "Web 2.0" look and feel, misses the mark with its Ajax features.
Comcast is one of those companies everybody loves to hate. Yet a quick glance at the latest version of the big cable operator's web presence reveals some surprisingly up-to-date visual motifs. With its easy-to-read text, expansive white space, candy-colored visual palette and simple calls to action, Comcast is far more modern-looking than its competitors. Time Warner Cable, DirecTV and Dish Network all offer cramped, console-style interfaces that wouldn't have looked out of place five years ago. But Comcast is clearly looking to incorporate the look and feel of Web 2.0.
Disclaimer: I'm a customer of Comcast and DirecTV but not of Dish Network or Time Warner, so I'm can't speak about the password-protected areas of the latter sites. Comcast's homepage is fairly similar to the other sites', but the rest of comcast.com looks strikingly different from your typical sales-and-service site.
Or so it appears. Once you actually click around the Comcast site, it becomes clear that most of its freshness is merely visual. The functionality and user experience are just as inconsistent as we've come to expect from big corporate sites.
Problem: Wonky Login Module
The site includes two login modules: A traditional one on the homepage and an Ajax one elsewhere. When entering bad credentials into the homepage one, you get redirected to the standalone one, where a loading icon indicates an in-progress XHR. Sometimes, that XHR hangs ... forever. No graceful failure message ever appears. During the site's relatively frequent performance slowdowns, even correct login credentials can result in a permanently hanging Ajax call. That tends to confuse users. The validation scheme is even more confusing. Blank required fields earn you a JavaScript alert box, while errors from the server side get loaded via XHR into into the markup.
Solutions
- Provide graceful failure for your asynchronous requests by setting a timeout on them. The XHR object doesn't offer this natively, but most popular libraries do.
- Use a consistent DHTML error-reporting framework rather than a grab bag of alerts and inline messaging. In addition to being more user-friendly, it will be easier to maintain.
- Build reusable components and, if necessary, style them differently on different pages. Don't build two overlapping components with strange dependencies.
Problem: Inconsistent Shopping Cart
When you visit the Comcast.com to shop for new service, the shopping cart utilizes a strange mixture of DHTML, Ajax, popups and traditional navigation to guide you through the process. On the first page view, before you've even added any services, a loading icon signals that an Ajax call is in progress. As it turns out, they're making an XHR just to load an empty shopping cart. As you add services from multiple tabs, Ajax is again used to update the shopping cart. But to remove items from the cart, you must click an "edit" button and do so in a popup window.
Most puzzlingly, the interface doesn't seem to validate your choices. I was able to add separate phone, cable and internet products to my cart, then add a bundled "Triple Play" phone/internet/cable package. I went very far down the checkout funnel without ever receiving a notification that I was ordering an incompatible array of products. Yet when I cleared out the cart and just played around with the standalone cable products, the interface kept me from breaking the rules. If I added cable package A, then added the mutually exclusive package B, package A disappeared from my cart. Yet there was no messaging to explain what had happened.
Solutions
- Don't use Ajax for just one aspect of your component. If the user can add items inline, she should be able to remove them, too.
- Let your users know what's going on. If you're going to use validation logic to remove things from their cart automatically, then message them when you've done so.
- Model your GUI widgets on traditional form controls. Mutually exclusive options should behave like radio buttons; a la carte ones, like checkboxes. A laundry list of options, some a la carte and some mutually exclusive, is usually a bad idea. Group each set of logically related options into something resembling a fieldset.
Problem: Inconsistent Global Navigation
Once you're past the homepage, with its left nav column, comcast.com presents you with a consistent top nav bar: Learn, Shop, Programming, Customers, About, and a search box. But the tabs themselves aren't clickable; you have to drill down within the DHTML menus to select a specific topic. Certain topics inexplicably load new windows, often from separate subdomains, full of Flash or HTML content. The navigation on these windows is different from the main site - or totally absent.
Solutions
- Study basic usability. The tabbed navigation metaphor has been around for ages. Follow best practices when implementing it.
- Consolidate your content. If you can embed a Flash movie in a popup window, you can embed it in your main window. It's jarring for users to be sent off-site without warning.
- Don't disorient your users. Your navigation doesn't need to be identical in every sub-domain, but do at least provide a consistent way to navigate back to the homepage.
Problem: Slavishly Consistent Color-Coding
Each section has its own design scheme in which headlines, buttons, links and tabs all appear in the same color. Links aren't even underlined. It's therefore impossible to tell, without mousing over an element, whether or not it's clickable. Users often have to play target practice and click on a small "go" link to get to a subsection; the headlines themselves are inconsistently clickable.
Solutions
- Underline your links and make buttons look like buttons. UI design isn't art; it's science. Users know the rules and get annoyed when you break them.
- If you must abandon underlined links, then do something to differentiate your links from other content. A pretty color palette is useless if it causes users to click continually on the wrong elements.
- When in doubt, make it clickable. Don't just link a button when you can link the accompanying image and/or headline, too.
Problem: JavaScript Users Only
If you visit comcast.com with a JavaScript-disabled browser, almost nothing works. There's not even an old-school "please turn on JavaScript."
Solutions
- It's 2007. Follow web standards. Use progressive enhancement. If you're not building a cutting-edge RIA with heavy client/server data exchange, there's no reason to require JavaScript. At the very least, inform your users that their browser isn't supported.
Conclusions
Most large corporate sites can't retool themselves overnight. At best, they can update their features one at a time and use fresh visual approaches to call out their new interactivity. But in doing so, they should rely on old-fashioned user exerience design, follow industry-standard UI conventions and strive for a consistent experience. Comcast's bright, big, bold design scheme is a welcome development, but it's only the first step in what could be a comprehensive UI redesign.
Technorati Tags
Topics: Ajax Examples, Ajax Intervention
Joel Spolsky and the Perils of Reasoning by Historical Analogy
Reasoning by historical analogy can be dangerous, especially if such reasoning is untempered by recognition that no two historical events are identical and that the future is more than a linear extension of the past. The instructiveness of historical events tends to diminish the greater their distance in time and space from the day and place they occurred.
-- PERILS OF REASONING BY HISTORICAL ANALOGY: MUNICH, VIETNAM, AND AMERICAN USE OF FORCE SINCE 1945 by Jeffrey Record
It may seem a little hyperbolic to quote from a paper published by the Air War College in advance of a critique of Joel Spolsky's latest strategy letter, but lessons about historical reasoning can apply just as well when the question is the future of software as it does when the question is war and peace. So, how exactly did Joel screw up in his analysis of the future of Ajax? Well, first to what he got right:
- He got the bit about the Forms-based interfacre (Green Screen, etc.) right. Web 1.0 was like the mainframe apps, Web 2.0 is like the desktop GUI. Welcome to the club, Joel, over a year and a half later.
- Large JavaScript apps will download faster over bigger pipes (or "tubes" or "trucks") and run faster in newer browsers with better JavaScript runtimes. So nobody cares about the 3k do everything library anymore, just like features are more important that memory footprint and performance in Desktop UI's. Again, welcome to the club.
- The portable programming language is not likely to be Javascript in the long run. Think VM, like Tamarin or Silverlight. The same developments that make JavaScript run faster in the browser will ultimately make it irrelevant.
So where did Joel go wrong?
- For one, he confuses the categories of Hardware Platforms, Operating Systems, UI Toolkits and Application Software. Anyone remember the RogueWave GUI libraries, circa 1994, or Think's Lightspeed C for the Mac from way back when? Where are they now? (RogueWave is still around, as is Symantec which acquired Think C, but you wouldn't exactly say they were the "winners" when it came to GUI SDK's.)
- What are the applications, the 1-2-3's of the web age? Well, everyone who publishes a web site is an ISV. Some make very basic use of the platform's (browser's) features. Some who publish full on webapps make fairly sophisticated use of them. As a group they have more leverage over the OS/Browser than Lotus 1-2-3 and company ever had. That's why IE can't make crazy extensions W3C standards, just incremental ones.
- Compilers and languages have come a long way since C showed the way. The norm now is for runtimes to support multiple languages with a common API (see .NET, etc.). So no "single" language will need to be invented.
- NewSDK looks a lot like GWT. Sorry, Joel, Google isn't snoozing. They may still get overtaken, but your narrative is a little off the mark.
What is the hardware, the OS, the GUI SDK and the Application? You could take the naive approach and say that Intel is still the hardware, Windows XP/Vista is the OS, but that doesn't quite square with how I see things. I think that the browser is the OS, DOM and Javascript are the GUI foundation library, and Dojo, Ext JS, etc. are the RogueWave and ThinkC SDK's of the Ajax age. As the OS/GUI library changes (new features/standards in the browser, etc.), so these SDK's will have to scramble to keep up. They will be influential, but eventually more and more of core GUI functionality will make its way into the browser. The browser calls the tune, everyone else just dances along.
Technorati Tags: ajax, spolsky
Topics: Ajax Development, Editorial, GWT
DOM methods, document.write and the art of library design
So I ended up doing some last-minute fiddling with the Really Simple History 0.6 beta before posting it for testing over at Google Code. Matt Snider pointed me to a potential SSL problem with using DOM methods rather than document.write to insert IE's hidden iframe. I've got four places where I need to insert stuff into the DOM, and I had already hemmed and hawed quite a bit about whether I should use DOM methods, document.write or a mixture. For now, based on Matt's comments and the verbosity of DOM methods, I've reverted back to using dirty-but-concise document.write. I'm going to continue testing this in as many browsers as possible before settling on a permanent solution.
While fiddling, I discovered something interesting that contradicted yesterday's (now-corrected) post. I originally wrote that if you've got script-generated DOM elements that need to be treated as native to the document (so, for instance, you can persist form values across an entire session regardless of whether you navigate off-site), you must use document.write to insert them into the DOM. Not true, as it turns out. It doesn't matter whether you call document.write or standard DOM methods from the head of your document. Either way, both methods seem to result in "native" HTML form fields that can properly persist values. Looking at Firebug or Opera's developer console, you can see that these elements end up being children of the body element even though they were, in fact, inserted into the head element. Modern browsers are so smart!
This whole issue of when to generate DOM nodes brings up an interesting facet of library development: Deciding how much stuff the end user (i.e the developer who is leveraging your library) has to do in the actual document. For most libraries, it's not an issue, because their objects and methods aren't going to do anything until called by application code. But it's different for something like Really Simple History, which relies on a variety of browser-specific hacks, many of which need to be set up before the DOM finishes loading. Sure, you could include inline script blocks in the body of your document to write the hidden, browser-specific DOM elements that enable your library to function. But developers really hate it when the use of a library forces them to fiddle with their page templates. Library authors have to get creative - for instance, by calling their initialization methods in the library file itself, even though that will result in DOM elements getting written to the document head.
As I said in yesterday's post, Ajax history management works only thanks to a variety of browser quirks and hacks. If you want clean code that doesn't break any standards, then you should cross history management off your list of requirements.
Things get even more interesting when your browser-specific DOM hacks work best when they're included as actual markup. My beta is out there, but I'm still scrambling to figure out the best strategy for Opera which, thanks to a bug introduced in 9.x, relies on a hack involving an image tag a crazy URL:
<img src="javascript:location.href='javascript:dhtmlHistory.checkLocation();';" style="visibility:hidden" />
This image throws errors in IE, so I couldn't tell developers to include it in their actual markup even if I wanted to release a library with such brittle implementation rules. If I want it to go in the actual HTML, I'd have to ask developers to do server-side browser sniffing and include it only for Opera users. YUCK. Yet all of the methods of writing it to the DOM via script have drawbacks. The way I'm doing it now, it works in Opera, but it throws an exception in the JavaScript console. Sure, only developers will see that exception, but still.... I guess I still have my work cut out for me.
Technorati Tags
Topics: Ajax Frameworks, Browsers, Javascript, Really Simple History
Coming soon: Really Simple History 0.6 beta
Late tonight over at Google Code, I'll be posting a beta of Really Simple History 0.6 for testing. The goal is to elicit help from RSH users in chasing down any bugs I've failed to catch, then push out a stable release around Halloween.
I've tried to be as ambitious as possible with this release: full support of IE7/Win, Safari/Win, Safari/Mac, Opera/Win, Opera/Mac. I've didn't quite get there, but I got close.
Features in the new version include:
- Full support for IE7/Windows (though my only Windows machines use IE7 Standalone, so I need help testing on "real" IE7 installs).
- Full support for Safari 2/Mac (though I'm still trying to eliminate the "infinite loading" bug before I push out the beta).
- Partial support for Safari 3/Windows (hampered by bugs in the current beta version of the browser).
- Full support for cross-platform Opera 9.22 (though you may need to hard-code an image into your markup).
- A totally revamped test page that allows you to play with the library in your browser of choice and see how it works behind the scenes.
As always, RSH works beautifully in Firefox 2 for Windows and the Mac. I hope to give it a good shakedown on Linux browsers in the next release.
So what is Really Simple History, and why am I updating it?
An Ajax bookmarking and history-management framework originally developed by Brad Neuberg, RSH became my responsibility a little over a month ago. I tinkered with it for a few weeks, then finally camped out with it for most of the past week to get a release out.
This is the first time I've ever contributed in this manner to an open-source project. It's been a lot of fun, but it's also been maddening, as anybody who's ever dug into the bowels of cross-browser history management can tell you. Here's a sampling of what I've learned from RSH:
Safari is crazy
Plenty of people who've worked on Ajax bookmarking projects have commented about this, but it only becomes clear once you've actually seen it in action. Getting this thing to work in Safari 2 for the Mac took a wildly disproportionate amount of time considering its market share. I wouldn't have been able to do it without Bertrand Le Roy over at Microsoft, whose blog entry on the development of the .Net history manager pointed the way for both Safari and Opera.
As Le Roy and others have noted, the Safari 3 Windows beta is so buggy that history management is hopeless. You can enable the back button for Ajax apps, but once you use it, the forward button becomes disabled. I noticed yet another wrinkle in this behavior (skip ahead if you're easily bored):
Navigate to a non-RSH site - Google, for instance. Then travel to an RSH site, create some history entries via RSH, and use your back button. The forward button stops working: a known bug. Now keep hitting back until you get back to Google again. Suddenly, your forward button works again. Hit forward and land back in your RSH app. Magically, the forward button continues to work.
If I hadn't spent so much of the last week lost in Safari-land, this interesting behavior might be worth further investigation. For now, I'm just hoping the Safari 3 team fixes this before the final Windows release.
Don't try to retire document.write just yet
A couple of different RSH users suggested getting rid of Brad's original calls to document.write in favor of standard DOM methods for adding elements to your page. That approach worked for some elements, but not for others.
In IE, RSH writes a hidden iframe into the document and uses the location and history of that iframe to help it track application state. Writing the iframe with document.createElement works just great.
But for all browsers, RSH uses a hidden textarea to store the entire history stack behind the scenes. This powers one of RSH's coolest features: its ability to retain history even if you navigate away to another site and then come back to your RSH application. This works because modern browsers retain form-field values throughout an entire browser session. But they do so only for form fields that exist in the DOM natively - that is, exist in the actual HTML markup or get inserted via document.write get inserted into the DOM before it's finished loading.
If you create a form element after your DOM is already loaded, the browser has no way to persist values in that element after you leave the page. Each time the page loads, even from the cache, you essentially create a virgin new form field. I'm therefore using document.write for the hidden textarea - and for the hidden form field I've added to RSH for Safari support.
UPDATE: As it turns out, it's immaterial whether you use DOM methods or document.write. The important thing is to use either method before onload fires. I ended up using document.write in the 0.6 beta because of SSH concerns and the fact that it's so much more concise. For more on this topic, see this subsequent post.
Because of the way RSH is structured, these elements actually get written to the head rather than the body of your document. Still, it works, and it should only offend the most anal-retentive of standards geeks. After all, if you're hacking the browser 10 different ways from Sunday just to enable Ajax bookmarking, then inserting a bit of non-validating markup via JavaScript is hardly the worst of your sins.
RSH won't be hitching its wagon to [insert name of your favorite framework here]
A few users suggested rewriting RSH in Prototype so it would be more compact. I appreciate the impulse, but I think that defeats one of RSH's chief virtues: the fact that it's written in Plain Old JavaScript and doesn't lock you into any specific Ajax framework. It plays well with any library you want it to: Prototype, jQuery, YUI, whatever. (If it doesn't, please file a bug so I can find out why.)
A little JSON never hurt anyone
The one library that RSH does require is a JSON parser; it ships with the latest open-source version. RSH 0.4 included an earlier version of the parser in the same file as its native code; I've broken it into a separate file under the logic that many users will already be serving a similar library. RSH's methods don't actually call toJSONString or parseJSON directly; instead, I've provided bridges so that you can hack in your own JSON methods without having to modify the guts of RSH itself.
Future roadmap
I've got quite a punch list for the next release:
- Provide minified versions of RSH and JSON for download
- Make use of Crockford's module pattern for better encapsulation
- Add official support for Linux browsers, Safari 3/Mac and Safari 3/Win
That's the future. For now, I have to get 0.6 packaged up and ready for testing. Check Google Code late this evening or first thing tomorrow.
Technorati Tags
Topics: Ajax Frameworks, Browsers, Firefox, IE6, IE7, Really Simple History, Safari
Project Flow
There are a lot of nice things about Agile Development from a BA perspective.
The one I like most is one of the corollaries that stem from the Agile Manifesto's decree that Agile Teams are self organizing.
Since I'm a consultant, I need to create a TLA (Three Letter Abbreviation) of a sexy, ridiculous (can you say 'mashup'?) or metaphoric term, send it to the marketing department and add 2-6% more to your bill because of my creativity. The Agiprop (Agile +Propaganda as opposed to the original Aggitation + Propaganda from the second red scare of the 1940s, get it?) I endow this new TLA as:
(c) 2007, Pathfinder Associates, LLC)
Anyway, we decided prototypical use cases took too long, nobody reads 'em and we have to move fast.
User stories? Don't have a customer team member empowered to make decisions, much less write 'em. I'll write 'em with my best guesses and incorporate them in overlying functional specifications.
Well, said our SCRUM Coach, let's take a design meeting.
Monday: sketch, discuss, argue for an hour or two to model and generate agreement on each 'major' feature.
Monday through Wednesday:
- BA (Business Analyst) guy heads off to create a functional specification and post to the wiki- leaving pointers for wireframes.
- IA (Information Architect) goes off to create a wireframe.
- BA and IA discuss informally when IA doesn't read what BA wrote or BA doesn't properly integrate wireframe intention.
- Developers code base functionality.
By Friday, the functional spec cum wireframe is on the wiki for the team to read, comment upon and prepare for final revision run through on the second Monday of the sprint.
Guess what?
Nobody read it until they started coding.
So Mondays now include a Review session, when the developer(s) assigned meet with the BA, IA and Architect to make sure we have everything covered- usually takes a half or or so before or after a design session.
Developers roll into the code with a vengeance and have a prototype ready to demonstrate to the customer on Tuesday or Thursday. BA takes notes, adds to the specification or to the backlog (as appropriate). This turns out to be our major interaction with an end user.
Typically, two demos are done for each simple feature- a 'rough draft' and, with user notes, a 'final draft' and we move on to the next feature.
The Team gets anywhere from three to eight major features rolled into each four week sprint with this routine.
We're about ready for the first code freeze for deployment of the beta, have 95% of the base functionality ready for a fairly complex web application and we're pushing down the bug list daily.
Not bad for a first shot at Agile for this BA. Of course a team of three exceptional Developers, a highly experienced architect and a wonderful IA made this team work well... with very few late nights or 'crunch' sprints.
I'm getting to like this while thing.
Next up: Are BAs necessary for the typical Agile Team? (Guess what the answer is)
Powered by ScribeFire.
Echo3 Update: SVN, Wiki, Forms, Builds
Echo3 is showing a few more signs of life. Since my update last month on some early details of Echo3, the pace has picked up. No alpha release, but already there are two forums, one especially for folks looking to contribute to Echo3 development. Also, a few other things worth mentioning about Echo3:
- The SVN repository can be found at svn://svn.nextapp.com/echo3/trunk (Echo3Extras are at svn://svn.nextapp.com/echo3extras/trunk).
- If you just want the binaries (or binaries with source), the Echo3Go project is handy.
- Initial performance numbers of Echo2 vs Echo3 show a more than 2x improvement in performance.
Further, a more detailed description of the new features, design principles and ideas behind Echo3 can be found on the wiki. Two items that are especially interesting for those looking to write their own components:
- Automatic Serialization: Data objects sent between client and server can be automatically serialized between Java, XML, and JavaScript. The serialization architecture is extensible--serialization code for new object types may be added by the developer.
- Simplified Client/Server Synchronization Peers: Serializing components and commands between client and server is performed automatically using the built-in serialization architecture. The component developer only need specify which properties should be sent (for components, all local style properties are automatically sent).
Serializing and deserializing data between client and server can be one of the more timeconsuming and error prone parts of developing Ajax apps. Packaging this into the framework with improve productivity at the very least.
Technorati Tags: ajax, echo3, echo2
Topics: Ajax Frameworks, Announcement, Echo2, Echo3
Afraid of LIE (LazyInitializationException)… Don’t Be.
All the fuss around LIE reminds me of my days when I was scared of NPE (NullPointerException). No matter how hard I tried, I just couldn't write code that couldn't run into NPE. Slowly, I learnt that it is not a question about not running into NPE, it is about implicit awareness about the possibility of any reference being a null at any given place and time in code. Isn't LIE very similar to NPE in that way?
Folks are afraid of switching from Hibernate 2.0 to Hibernate 3.0 because their app starts throwing LIE everywhere as soon as they do. So, instead of trying to figure out the reason for this. They switch back to 2.0.
Follow these simple rules and we can avoid LIE in most places:
- Use OpenSessionInViewFilter (OSIV), it is your friend (as described here and here): Atleast in web applications, this ensures that you have a valid session in all layers - controller, service and finally view. One argument I came across recently against OSIV-filter is that it couples your application with Hibernate and makes it harder to replace persistence layer with some other persistence mechanism. An interesting thought! But does it really stick? Think about it. Any persistense framework will either not use lazy loading (like hibernate 2.0 did) or have some mechanism for loading object on demand ("lazy" that is).
- Avoid keeping reference to a hibernate managed entity outside of a hibernate session: If you need to keep an object around longer than a request (http-request or any other request), create a data-transfer-object out of your hibernate object. There are few common situations where this occurs most often. Currently Logged in user's information is retrieved from database when the user logs in and is kept in HttpSession. It is very easy to get into the habit of modifying this User object in HttpSession and trying to save it which will run you into Hibernate Merge issues. The easier (and Hibernate mechanism independent) solution is to create UserDTO and keep that in HttpSession. Another common situation is when you need to use caching to reduce database load. Again, why not use DTO(s) inside cache and not hibernate managed entities. It can be argued that this promotes struts action-form like anti-pattern ("bridge" anti-pattern?). However, I prefer keeping a known entity (fully initialized with a controlled hierarchy depth) around than a magical entity (hibernate object that may not have been fully initialized).
Just like NPE, once we ensure that an open connection to database (hibernate session) exists whenever we deal with a hibernate managed entity, we can avoid LIE.
Topics: Web/Tech
FriendFeed, Jaiku and Plaxo Pulse: Networks within networks
I'm as sick of signing up for new social networks as anybody. I'll never get back the hour I spent establishing an Orkut profile I never used just because two hipster friends momentarily thought Orkut was cool and badgered me into submission.
That said, I'm a little dismayed by the identity-management land rush. For a couple of years now, we've been hearing about this glorious world in which we'll be able to aggregate our online identities across multiple social networks. In just the last few weeks, I've gotten invitations to beta-test three new identity aggregators (FriendFeed, Plaxo Pulse and Jaiku). And now Facebook announces that it wants to make my data portable so I can take it with me to whatever network I want - a move unsurprisingly endorsed by Plaxo and other bit players.
Facebook's announcement is obviously a marketing move - just another step in its strategy to position itself open ecosystem rather than a closed network. But FriendFeed and its ilk are another matter. I have no doubt that the future will involve a procession of new, flavor-of-the-month social networks. But it's hard to imagine any one of these meta-networks building the ubiquity of the networks they cannibalize.
Most of these services fall into three categories: content aggregators, identity managers and reputation protectors. Content aggregators (such as FriendFeed and Profilactic) try to mege all of your "attention data" into a single stream for syndication. Identity managers (such as FindMeOn) seek to create a "master" online identity with permissioned access to all of your other identities. Reputation protectors (such as Naymz and ClaimID) help you establish and protect your online "brand."
There's a lot of overlap between the three concepts, but they all suffer from the same problems:
- They're too complicated to use: I gave FindMeOn a whirl about a year ago, but I found its system of "badges" and "digital keys" complex and annoying. It didn't help that its visual design and Ajax interface were so cluttered and quirky. FriendFeed, which is still invite-only, offers a much cleaner and more direct user experience. But its RSS mash-up strategy is far less ambitions than that of FindMeOn and its nebulous parent, Syndiclick. Regardless, none of these services really reduces the complexity of managing your online identities. If anything, they add to it, forcing you to keep one more profile up to date.
- They solve a problem most average users don't have: Tech professionals and early adopters may all have a zillion online identities, but most social-network users have at most a handful of accounts. As they discover new services, they're likely to stop using older ones. I loved Friendster as much as anybody back in 2003, but I never log on anymore because none of my friends do. Ditto MySpace circa 2005. I may have a trail of social-network accounts, but only a few are ever going to be truly active at any given time.
- They're a little too good at what they do: As earlier commentators have pointed out (here, here and here), social networks often derive much of their value from being walled off from one another. Users may want to share different data with friends, family members, colleagues and romantic prospects. Aggregating all of your identities just to re-segment them seems like too much work.
Is anybody out there actively using these services and, if so, how useful are they? As always, I'd love to hear in the comments.
Technorati Tags
Topics: Facebook, Social Networking
Desktop Applications Dying, Dying…
My post the other day on the death of desktop applications got me a large volume of hate mail. I was alternately an ignoramus or a hater. One common refrain was that Web UI's still sucked and would never replace Desktop apps in terms of the user experience (OK, it was usually not phrased so elegantly). I guess many readers missed my point. My point was that it rarely makes sense to develop a pure Desktop app anymore, not that everything should be a webapp. Why is that?
- In many cases and for many uses, Web UI's are as good as Desktop UI's. Look at all of the Ajax photoshop knockoffs (here and here), the various word processor or spreadsheet apps, and the direct manipulation interfaces such as Yahoo Pipes.
- The choice is no longer between the Desktop app and the Webapp, but between just doing a webapp or using something like Adobe AIR or Google Gears to do a Desktop RIA and a webapp at the same time.
- As the capabilities of browsers increase, with faster and more efficient Javascript engines, offline features, etc., and the maturity of Ajax frameworks evolve, the reasons for writing Desktop RIA's that can also work as webapps become more compelling.
Those that persist in yammering about how kludgey webapps are live in the distant past, confusing the Green Screen nature of the pre-Ajax (as I observed here in 2006, and Joel Spolsky did here over a year and a half later -- more on what Joel got right and wrong in a later post) with the current ability to develop Component GUI applications just like those Desktop apps.
My point remains unchanged: spending significant resources to develop a purely desktop app only makes sense in specific circumstances, and unless you have tons of money to write your own network integration systems, you are best off using the already available Desktop RIA frameworks.
Technorati Tags: ajax, desktop RIA
Ajax Intervention: Product tooltips in Amazon’s beta redesign
Welcome to Ajax Intervention, in which we dissect how major websites misuse, or fail to use, Ajax to improve their user experience.
Up this time: Amazon.com and its inconsistent new Ajax redesign.
The beta test for Amazon's new DHTML navigation has garnered plenty of perceptive commentary from the Ajax and UxD communities. (See posts from Ajaxian, Functioning Form, Jeffrey McManus and CommaDot.) Yet one puzzling bit of Ajax fuctionality hasn't gotten much notice: The inconsistent use of tooltips in item listings.
I've long bemoaned the fact that Amazon doesn't let me add an item to my cart, or to my wish list, from its search results and landing pages. To buy an item, I've always had to navigate to the item's individual product-details page. But that's all changed with the new redesign - sort of.

When I visit the new Amazon homepage, I see a module titled "What Do Customers Buy After Viewing This Item?" It contains thumbnails and headlines for three different products related to my most recent search. Next to the name of each product, I see a little blue caret graphic. Mousing over it, I'm presented with an extremely useful microcontent popup with some basic product details and two buttons: "Add to Cart" and "Add to Wish List." I've longed for just such a feature for years. It's as if Amazon has finally read my mind.

But ... wait a minute. Directly above and below the "What Do Customers Buy ..." module, I see two similar modules: "New For You" and "More to Explore." The former contains product suggestions; the latter, products I've previously viewed, or items similar to them. But both sets of listings lack the little blue caret graphic for which I've now been trained to look. I try to mouse over various portions of each listing, but no tooltip appears. For these products, I guess I still need to navigate to a details page to purchase them.


How about the search results page? A quick search for "Cory Doctorow," my new favorite sci-fi writer, returns three pages of results. The very first item is the one I'm looking for: the short-story collection "Overclocked: Stories of the Future Present." Once again, Amazon is reading my mind. But try as I might, I can't find a tooltip or an "Add to Cart" button. Once again, I'm forced to load an entire new page - with several scrolls worth of extraneous data - just to purchase something I've already decided I want. This isn't so bad when I visit the site to search for a single item. But how about those times when I come with a list of 10 new tech manuals to purchase? The number of pages I need to load is twice what it should be. God forbid I don't have broadband.
I understand why this sort of thing happens on big sites. Amazon runs tons of betas, often simultaneously, to gauge the effectiveness of individual UI tweaks based on rigorous metrics. Interface refinement is about testing new ideas without re-architecting your entire site or totally confusing your existing user base. I have no doubt that the search-results page and the three upsell modules I'm testing are all maintained separately, perhaps by separate teams. If the Ajax functionality in one of them proves successful, it will eventually make its way to the others.
Still, in the meantime, users are left with a UI whose inconsistency casts doubts about the validity of any data it generates. How can a new feature win over your users if it's applied arbitrarily?
Ironically though, unliike most of Amazon's little DHTML/Ajax tweaks, I think this one is executed almost flawlessly. You can barely see it on a fast connection, but there's a nice little animated "loading" bar graph to provide status on your XHR. The telescope effect on the tooltip itself is subtle but nice. I might quibble about the rendering logic, which allows the tooltip to scroll off the page rather than shifting it fully within the viewport. Still, I know how difficult that logic can be to pull off on a templatized, highly dynamic site. Overall, this is an extremely well though-out feature that should make it faster and easier for customers to drop some cash. Let's hope it makes it onto the entire site.
Technorati Tags
Topics: Ajax Examples, Ajax Intervention
Pimp my Webapp: Turning Web 1.0 into Web 2.0, Part 1
Everyone wants the Web 2.0. But how to get there, especially if you have a dowdy old Web 1.0 application? Will I have to spend the annual GDP of a smallish Central American nation on the rewrite? There are three general approaches that evolved over the last year:
- The Christmas Tree Approach - decorate your Web 1.0 app with Ajax widgets and simple backend JSON or XML services. Pro: doesn't require major investment. Con: app still mostly suffers from the Web 1.0 downsides -- postbacks, CRUD, etc.
- The Refrosting the Cake Approach - transform all of your views from HTML to JSON or XML. Develop a client side GUI that calls your applications controllers and views. Pro: doesn't require full rewrite. Con: control flow moves from server side to client side; won't take full advantage of RIA opportunities, such as direct manipulation or document-centric interfaces; really just a nice face on CRUD.
- The From Scratch Approach - take the opportunity to rethink your application as something other than the web equivalent of a green screen. Imagine Photoshop or Word as a traditional webapp. Pro: unencumbered by the old system. Con: costly; you may lose your way in reinventing your app.
I think approach #2, Refrosting the Cake, is actually quite appealing. You can make using that dowdy old webapp quite a bit more pleasant with a quick coat of Ajax. There was a really interesting article on this written by Brian Walsh back in July of 2006. It sort of got lost as a pure Tibco GI article, but it has much wider applicability. In it, Brian uses XStream to convert the views of a SpringMVC sample application from HTML to XML. He then uses Tibco GI to build a UI that talks to the controllers and views on the back end.
I used a similar approach to convert a dowdy old application -- mwhois -- to Web 2.0. Instead of Tibco GI, I used GWT. And instead of XML, I used JSON.
The old application looked somewhat homely...

...and suffered from the kludgey flow and heavy postbacks typical of Web 1.0. I proceded to identify the different views and converted them (via mwhois' templates) into JSON.
simple search: domain=agiledev&ext=com
{ "isAvail" : false, "domain" : "agiledev", "ext" : "com", "whoisServer" : "whois.crsnic.net" }
raw record: domain=french&ext=biz&show_raw=1
{ "domain" : "french", "ext" : "biz", "raw" : "Domain Name: FRENCH.BIZ\nDomain ID: D2708502-BIZ\nSponsoring Registrar: COMMUNI GAL COMMUNICATIONS LTD.\nSponsoring Registrar IANA ID: 418\nDomain Status: clientTransferProhibited\nRegistrant ID: GC683CO965021\nRegistrant Name: jamil akhtar\nRegistrant Address1: Regent House\nRegistrant Address2: 24-25 Nutford Place\nRegistrant City: London\nRegistrant Postal Code: W1H 5YN\nRegistrant Country: Great Britain (UK)\nRegistrant Country Code: GB\nRegistrant Phone Number: +44.7729391052\nRegistrant Facsimile Number: +44.2075693152\nRegistrant Email: jamil@cityfinancialcorp.co.uk\nAdministrative Contact ID: GC683CO965021\nAdministrative Contact Name: jamil akhtar\nAdministrative Contact Address1: Regent House\nAdministrative Contact Address2: 24-25 Nutford Place\nAdministrative Contact City: London\nAdministrative Contact Postal Code: W1H 5YN\nAdministrative Contact Country: Great Britain (UK)\nAdministrative Contact Country Code: GB\nAdministrative Contact Phone Number: +44.7729391052\nAdministrative Contact Facsimile Number: +44.2075693152\nAdministrative Contact Email: jamil@cityfinancialcorp.co.uk\nBilling Contact ID: GC683CO965021\nBilling Contact Name: jamil akhtar\nBilling Contact Address1: Regent House\nBilling Contact Address2: 24-25 Nutford Place\nBilling Contact City: London\nBilling Contact Postal Code: W1H 5YN\nBilling Contact Country: Great Britain (UK)\nBilling Contact Country Code: GB\nBilling Contact Phone Number: +44.7729391052\nBilling Contact Facsimile Number: +44.2075693152\nBilling Contact Email: jamil@cityfinancialcorp.co.uk\nTechnical Contact ID: GC683CO965021\nTechnical Contact Name: jamil akhtar\nTechnical Contact Address1: Regent House\nTechnical Contact Address2: 24-25 Nutford Place\nTechnical Contact City: London\nTechnical Contact Postal Code: W1H 5YN\nTechnical Contact Country: Great Britain (UK)\nTechnical Contact Country Code: GB\nTechnical Contact Phone Number: +44.7729391052\nTechnical Contact Facsimile Number: +44.2075693152\nTechnical Contact Email: jamil@cityfinancialcorp.co.uk\nName Server: DNS.INTER.NET.IL\nName Server: NS.COMMUNIGAL.NET\nCreated by Registrar: COMMUNI GAL COMMUNICATIONS LTD.\nLast Updated by Registrar: COMMUNI GAL COMMUNICATIONS LTD.\nDomain Registration Date: Wed Mar 27 00:01:00 GMT 2002\nDomain Expiration Date: Wed Mar 26 23:59:59 GMT 2008\nDomain Last Updated Date: Mon Mar 12 16:25:34 GMT 2007\n\n>>>> Whois database was last updated on: Sun Oct 14 17:51:14 GMT 2007 <<<<\n\nNeuLevel, Inc., the Registry Operator for .BIZ, has collected this information\nfor the WHOIS database through an ICANN-Accredited Registrar. This information\nis provided to you for informational purposes only and is designed to assist\npersons in determining contents of a domain name registration record in the\nNeuLevel registry database. NeuLevel makes this information available to you\n\"as is\" and does not guarantee its accuracy. By submitting a WHOIS query, you\nagree that you will use this data only for lawful purposes and that, under no\ncircumstances will you use this data: (1) to allow, enable, or otherwise\nsupport the transmission of mass unsolicited, commercial advertising or\nsolicitations via direct mail, electronic mail, or by telephone; (2) in\ncontravention of any applicable data and privacy protection acts; or (3) to\nenable high volume, automated, electronic processes that apply to the registry\n(or its systems). Compilation, repackaging, dissemination, or other use of the\nWHOIS database in its entirety, or of a substantial portion thereof, is not\nallowed without NeuLevel's prior written permission. NeuLevel reserves the\nright to modify or change these conditions at any time without prior or\nsubsequent notification of any kind. By executing this query, in any manner\nwhatsoever, you agree to abide by these terms.\n\nNOTE: FAILURE TO LOCATE A RECORD IN THE WHOIS DATABASE IS NOT INDICATIVE\nOF THE AVAILABILITY OF A DOMAIN NAME.\n" }
global search: domain=agilesoftware&do_global=1
{ "domain" : "agilesoftware", "avail" : [{ "domain":"agilesoftware","ext":"biz" },{ "domain":"agilesoftware","ext":"be" }], "unavail" : [{ "domain":"agilesoftware","ext":"com" },{ "domain":"agilesoftware","ext":"net" },{ "domain":"agilesoftware","ext":"org" },{ "domain":"agilesoftware","ext":"co.uk" },{ "domain":"agilesoftware","ext":"info" }] }
wizard search: do_wizard=1&company=pathfinder&keyword1=uxd&keyword2=agile&ext=com
{ "whoisServer" : "whois.crsnic.net", "avail" : [{ "domain":"pathfinderuxd","ext":"com" },{ "domain":"pathfinder-uxd","ext":"com" },{ "domain":"uxdpathfinder","ext":"com" },{ "domain":"uxd-pathfinder","ext":"com" },{ "domain":"pathfinder-agile","ext":"com" },{ "domain":"agilepathfinder","ext":"com" },{ "domain":"agile-pathfinder","ext":"com" },{ "domain":"uxdagile","ext":"com" },{ "domain":"agileuxd","ext":"com" },{ "domain":"uxd-agile","ext":"com" },{ "domain":"agile-uxd","ext":"com" }], "unavail" : [{ "domain":"pathfinder","ext":"com" },{ "domain":"pathfinderagile","ext":"com" },{ "domain":"uxd","ext":"com" },{ "domain":"agile","ext":"com" }] }
Then I wrote a simple, tabbed interface using GWT and the MyGWT widgets and slapped the two together.

I'll have more details on the code details in part 2 of this article. For now, you can look at the old and new interfaces.
Technorati Tags: ajax, gwt, mygwt, tibco gi, JSON, XML, web20
Topics: Ajax Development, Best Practices, Design Patterns, Google, GWT, JSON, Tutorials
Ajax Intervention: Tivo.com online scheduling
Welcome to Ajax Intervention, in which we dissect how major websites misuse, or fail to use, Ajax to improve their user experience.
Up this time: Tivo's My Tivo online scheduling tool, which could use an emergency Ajax intervention.
As much as I love my Tivo digital video recorder, it's no fun to schedule recordings on a television screen with a remote-control joystick and a virtual keyboard. But thanks to a wireless card and the online My Tivo service, I can schedule a program from any web browser as little as an hour before it's set to air. The service was originally billed as a tool for last-minute scheduling when you're away from home, but I use it even when I'm sitting in the same room as my DVR. Web interfaces are just easier than Tivo's on-screen menus.
That said, the My Tivo interface could use an update. Given the small number of ads that appear on the site - most of them 120x120 buttons with shallow inventory - it's hard to imagine Tivo is earning much money from all the extra pages its users are forced to navigate just to schedule a Season Pass of their favorite show. The process goes something like this:
- Visit the "Online Scheduling" page in My Tivo.
- Enter a program in the search box.
- Receive a results page.
- Click on a show's title.
- Receive a program details page.
- Click "Get a Season Pass."
- Receive the recording-options page.
- Choose your recording options.
- Receive a confirmation page with no compelling content.
That's a minimum of five full pageloads just to schedule one program, without a bit of Web 2.0 goodness in sight. Sure, there are some DHTML tabs at the bottom of the program details page. But that's about it.
I'm not just talking about the lack of Ajax, either. The Tivo set-top box is all about personalization; based on your ratings of shows you've recorded, it can predict which shows you might like and predictively record these "Tivo Suggestions" for you. But any such personalization is buried in the Tivo web interface, inside a DHTML tab at the bottom of the program details page.
Click it and you'll learn, for instance, that lovers of "Buffy the Vampire Slayer" also enjoy "Angel," "Charmed" and "The X-Files." But there's nothing to suggest these canned recommendations are based on my own viewing habits; in fact, I've given "Charmed" the dreaded "three thumbs down" rating on my own Tivo box and it's still showing up here. Why on earth isn't this content specifically targeted to me? If the content were compelling, maybe it wouldn't deserve to be socked away inside a tab.
Now let's imagine how My Tivo might look with an Ajax overhaul and better personalization.
- Visit the "Online Scheduling" page in My Tivo.
- Enter a program in the search box.
- Thanks to Ajax autosuggest, receive an inline list of the most likely matches. Click on the one you want.
- Receive a program details page.
- Click "Get a Season Pass."
- Thanks to the power of Ajax, receive a lightboxed recording-options dialogue and choose your options without leaving the page.
- Within the same lightbox, receive a confirmation message that includes personalized recommendations for additional shows.
By replacing three page refreshes with Ajax calls, we can reduce the process of scheduling a Season Pass down to two pages and, with better data mining on the server side, throw in personalized recommendations, too. If you've noticed that the UI I'm describing is a complete Netflix ripoff, well, duh. Why shouldn't Tivo - the company that invented the DVR market and then watched inferior operators eat away at its market share and profitability - take a page or two from the playbook of the company that's almost single-handedly decimating Blockbuster? Netflix operates like an Internet company, not an entertainment company. Tivo should follow suit.
Sure, Tivo continues to leverage wi-fi, desktop software and content partnerships into an impressive array of services. Its set-top boxes really can function as wireless entertainment hubs. But Tivo behaves, fundamentally, like a moribund hardware maker. It treats its web offerings like inferior adjuncts to the set-top experience, thereby neglecting a powerful means of product differentiation. And really, with the entire country laying odds on how long you'll stay afloat, shouldn't you pursue every possible avenue to improve your product?
Crappy cable-provider DVRs lack Tivo's intuitive UI and powerful wireless integration, but they're in a lot of homes thanks to competitive pricing and the marketing muscle of Comcast, et al. Meanwhile, true geeks can roll their own DVRs using commodity PC hardware and open-source software. Tivo's best hope for the future involves beating the cable companies on features and beating the DIY crowd on ease of use. A solid web UI would be a nice step in that direction.
Topics: Ajax Examples, Ajax Intervention
About Pathfinder
Recent
- Dealing With A Legacy
- Big Changes Underway at LinkedIn for Groups
- Four blatant iPhone usability blunders (and one constant annoyance)
- Flash/Flex physics engines and examples
- A Rails Story, Or An Engine That Really Could
- Data visualization and the art of conveying information
- What’s In Your Junk Drawer?
- Selling Git on the Business End
- IE8 Beta 2 Released
- Faster JavaScript for Firefox 3.1 Thru JIT
Archives
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006














