Lessons in UX
I rarely talk about my work projects on my blog, but we’ve finally completed a project which is worthy of showing off. I’m the application manager for Nationstar Mortgage’s Loan Origination System (LOS). I have a small team of great Java developers working for me. Our system has both an internal and external facing component, so I’ve got two sets of users to please.
Around last October, we noticed a downward decline in the satisfaction rating of our external facing site. The marketing department takes monthly surveys of our users and circulates the reports with the management team. Our management team decided that we needed to do something about it. We weren’t going to be able to grow external business with our existing site. Several ideas were tossed around, but I finally suggested with bring in some usability expertise to help us give the site a better user experience.
After filling them in on what Usability and User Experience (UX) were all about, and that there are people highly specialized in doing just this kind of thing, they got behind the idea. Now the trick was to find the right experts. We talked to a couple vendors, but ultimately settled on Improving Enterprises. While it helped that I’ve known their management team for about a decade, what really sold the ultimate decision makers was their expertise and vision.
We started with a two-week analysis engagement. The Improving UX guys would talk to samplings of all the users of our site. They also went through the site themselves, including the workflow. We even had them sit in on a new-hire training class for the system. The result of this engagement was an impressive set of design comps and an extensive list of recommendations to improve the usability of the system.
We then had them put a UX expert, David, on site with about half of my Java team to work on putting a new face on the external site. As is always the case, there was a lot deadline pressure, so we had to comprise where it made sense. I had a specific goal for Improving of providing the templates we would need to carry this initiative forward after the initial engagement. This meant I wanted css, stylesheets and html files covering typical page layout scenarios so that my team could apply them as needed.
The six weeks with David blasted past pretty quickly. We actually extended him for another month to come in one day a week to validate we were on the right path and get us unstuck when we ran in to scenarios we hadn’t anticipated. My team worked their butts off to hit a tight deadline, and we’re finally deploying tomorrow night.
Here’s a preview of what our external users will get to experience Thursday morning. I’ll compare the old to the new, starting with the login page:

Now normally this wouldn’t be considered too bad, but it typifies the problem with the old site not matching the corporate brand. The colors on the old site were what we affectionately referred to as the Denver Broncos colors. The new login page changes all that:

The new login page nails our brand perfectly, and the blue box demonstrates some of the work we did with improving the consistency of messaging to the users.
Here’s the landing page for old site. Users would see this page immediately after logging in:

Although it is not visible in this image, the navigation links on the left have JavaScript-driven submenus for some items that drop down on hover. None of this was very intuitive for a new user. Here’s how we changed it:

We eliminated the confusing navigation options and narrowed it down to the four primary options across the horizontal bar at the top. There is still a bit too much white space around the filtering options, but I’ll gradually tighten that up.
Here’s the old status page for a case once the user has clicked one of the links on the above landing page:

The bright yellow on the left was how pages with errors were indicated. Counterintuitively, green was also used to highlight a different category of errors. And it was still never really clear what a new user was supposed to do next. We addressed this shortcoming with the new page:

Navigation options are greatly simplified. The left navigation is for hopping to specific sections of a case. We also use icons to indicate sections which have errors. The biggest improvement is the Continue button at the bottom. A new user can literally complete the entire process by clicking that button. They are navigated through all the required pages, all the way to sending the case to our fulfillment system. The power users can still use the left navigation tree to hop to specific sections of our application. We also greatly improved the status display. The green bar at the top is always visibile when a user is working in a case, and shows the status relative to the prior and next steps on the progress bar.
So that’s the sneak peek, now for some observations and lessons learned.
- Hire good people – I know this sounds obvious, but UX is actually a discipline, and you want people trained and experienced in it. The typical web developer is not a UX person. Good UX people have opinions on how you should improve things and are closer to artists than developers. Listen to them.
- Don’t pay someone to tell you you suck – This is related to #1 above. We talked with one vendor who wanted to provide a very detailed analysis of the ways our website sucked. This would have been a map of where we had been, not a path to where we wanted to go. If you think your site sucks, it probably does. Don’t waste money confirming the suspicion, fix it!
- Usability is more than lipstick – I hit on this a little above, but UX is about more than changing colors and buttons. We made fundamental changes to how a user interacts with our system with the goal of giving them a more pleasurable and intuitive experience. A good UX person should be helping you more than just creating pretty buttons and gradients. We addressed page layout, site navigation, page flow, button consistency and user messaging, in addition to applying the new theme.
- It will take you longer than you think – Even with three developers, updating our legacy Struts/Hibernate site was a bear. We ending up taking a compromise approach for the first release. We fully redesigned the most critical pages, and then only cleaned up the look and feel on some pages. We’ll be making another pass through the system to get those pages.
- Learn to fish – We knew we would only have our UX person for a limited amount of time. Ensure you get what you need to help carry the effort forward after they’re gone. In our case, these were the page templates (html, css, images, javascript and Photoshop files). You may even want a style guide, although those can be time consuming to create. Either way, your developers should be able to produce new pages using the theme after your UX person is long gone.
- JavaScript is your friend – We made extensive use of JQuery and JQuery UI in redoing the site. There were some things where it was much easier to apply a style and position or wrap an element using JQuery than to make extensive changes to server side code. We ended up producing a JQuery UI theme branded with our company colors that we can now reuse for other projects.
This has been an exciting and hectic project. I want to thank my team (Deren, Kevin, Smitha and Ajay), along with the UX guys at Improving Enterprises (Travis, Dustin and David). They all did an excellent job. It was great to work on a project that can have this significant an impact for our users, and we’ll be keeping our fingers crossed that everything works as planned.
All images © 2011 Nationstar Mortgage, and may not be reused without permission
A Note on Helpers
In my previous post on Spring and ExtJS, you might have noticed the usage of a class called ExtData in the methods of the ContactController. I didn’t explain it at the time, but want to clarify what it is and why I created it.
There is a lot of boilerplate code involved in sending a response back to a request from ExtJS. You’re always going to return a Map, which has a success property, and possibly data, total and message properties. A typical response would look like this:
This gets annoying after you’ve done it a couple dozen times in the same application, so like every good (lazy) programmer, I implemented a simple class to deal with this. Take a look at the ExtResponse and ExtData classes in the org.sporcic.extjs package.
ExtResponse is the base class that simply deals with the success and message properties. The message property is only serialized if if is not null, thanks to this Jackson JSON attribute:
The ExtData class extends this class and knows how to deal with the data and total properties. It provides a simple method to add data to an internal list and correctly calculate the total property. This simplifies the controller methods to look like this:
Technically, I only removed one like of code from the previous example, but using the ExtData abstraction makes the code easier to read and eliminates tracking down a hard-to-find error in case you mis-type the name of one of the properties.
More ExtJS and Spring
It has been a while since I wrote my previous post which outlined a sample application using ExtJS and Spring. Since then, we’ve seen a new major version of both frameworks released, with ExtJS up to v3.3 and Spring sitting at 3.0.5.
ExtJS added a lot of cool features on the path to 3.3, but the most significant amount of cool stuff happened with the release of Spring 3.0. This release of Spring made it significantly easier to use JSON and REST, which eliminated a lot of the hackery that I had to do in my template with Spring 2.5.
I’ve been working on an updated version of my template, which makes use of all these new features, and decided to present it as a work-in-progress. The first part I want to talk about is how to get an Ext.data.JsonStore talking to a Spring MVC controller for CRUD operations. Loiane Groner wrote a pretty nice post on getting this wired in with an EditGrid, but it missed some of the real coolness with Spring 3.0.
I’ve pushed my sample application to GitHub to make it easier to get the big picture. The sample is a very simple webapp which uses a single domain object called Contact. The full project includes the Maven POM file along with a whole project which uses an HSQLDB with a full MVC stack in Spring. I’m going to ignore everything below the controller for this tutorial, but you can check out the rest in the full project.
Let’s start simple by demonstrating the GET operation, which will retrieve a list of all the contacts we have in our repository. Here is the application snippet from ContactController. Note, I’m using images so I can easily highlight sections. You can grab the raw source from the GitHub link above.
So the easy stuff first. I’ve annotated the ContactsController class with the @Controller stereotype from Spring to enable auto discovery. The @RequestMapping attribute says that this controller with catch all requests for ‘/contacts’. The getContacts() method is setup to catch any HTTP GET request, thanks the @RequestMapping annotation on the method itself. Finally, the real magic happens with the @ResponseBody annotation on the method return value.
@ResponseBody tells Spring it should not try to find a view and should just encode whatever object you are returning and send it back to the browser. Since we’re going to make an XMLHttpRequest from the browser, Spring will automagically encode the response in JSON format. The only caveat is that the Jackson JSON processer must be on the classpath, which my Maven POM file takes care of.
On the client side, the App.js file defines the Ext.data.Record, Ext.data.Reader, Ext.data.Proxy and Ext.data.Store. For simple applications, it is usually overkill to declare them like this, but I’m explicitly defining them to show how they will integrate with the Writer for updates.
For the Proxy, I’m setting restful to true, which means it will use the HTTP verbs GET, POST, PUT and DELETE for the CRUD operations. The url is set to send all those to the our controller above.
To make things interesting, I include a date field in the definition of the Record. This is used to show off one of the cool features of Jackson JSON and how it handles serialization.
Finally, I create the Store with the Proxy and Reader. I set autoSave to false, so I can manually force saves and loads from the console in Chrome.
In the current state, I haven’t wired in any widgets, so I’ll use the console to exercise the store. If you run the WAR file after generating it with Maven (mvn package), you can open up the JavaScript console in Chrome when you’re on the main page. Here’s how the store is loaded:
After executing the load() method of the store, you can see it loaded 10 items. If you enabled resource tracking, you can see the actual request looked like this:
The response is a JSON string that looks like
{"data":[{"id":10,"firstName":"Robert","lastName":"Bluegill","dob":"1975-06-04"},{"id":9,"firstName":"Lavern","lastName":"Knuckles","dob":"1980-12-16"},{"id":8,"firstName":"Kim","lastName":"Lavendar","dob":"1971-05-22"},{"id":7,"firstName":"John","lastName":"Cogsley","dob":"1965-10-15"},{"id":6,"firstName":"Larry","lastName":"Grissom","dob":"1983-04-01"},{"id":5,"firstName":"Larry","lastName":"Stewart","dob":"1981-08-08"},{"id":4,"firstName":"Jill","lastName":"Angel","dob":"1977-02-20"},{"id":3,"firstName":"Brandon","lastName":"Smythe","dob":"1968-11-10"},{"id":2,"firstName":"Susan","lastName":"Smith","dob":"1976-04-13"},{"id":1,"firstName":"John","lastName":"Smith","dob":"1984-07-03"}],"total":10,"success":true}
This is the typical response an Ext.data.Reader is looking for. Notice that the dates are correctly formatted as YYYY-MM-DD. This is handled via a custom attribute on the Contact domain object:
The method itself returns a Date. Without the @JsonSerialize attribute, this property would be serialized in the JSON response by calling its toString() method, which is not a desirable outcome. The ExtDateSerializer class does custom serialization of the Date object to convert it to a String using a DateFormat. The @JsonProperty annotation configures what name the property should have when serialized to a JSON object. Without this annotation, the property would have the name birthDate. I’m overriding that, specifying it should be called dob when serialized.
Now lets try to go the other direction and write (POST) a new Record from our Ext.data.Store to the ContactsController. Here is the (incorrect) Writer. We’ll get to that “incorrect” part in a minute, but first the easy stuff:
You must set encode to false, or else the Writer will try to send the payload as HTTP form data, not JSON. The error you get looks like this if you don’t set encode to false:
Note the HTTP error code is 415. Every other error you get will be a 500. It is only if you don’t set encode to false that you’ll get a 415.
Next we set writeAllFields to true. If you don’t do this, only the properties that have changed for a Record will be transmitted. We want everything server side for deserialization, so this ensures the whole object shows up at the server.
Finally, I set listful to true. This is hugely important for getting JSON deserialization to work correctly in the controller. This option says to wrap all updates inside a JSON array, even if there is only a single Record being sent. Since you can’t overload controller methods in Spring MVC controllers, we need to be able to catch both single and multi-record updates with a single method. Setting the writer to listful ensures that happens.
The controller method catching our new Record looks likes this:
The @RequestMapping annotation says that this method will catch all POST requests to the /contacts URL. The @RequestBody is new in Spring 3 and is the incoming analog to @ResponseBody. It basically tells Spring to attempt to deserialize the incoming payload into a Java object, in this case an array of Contacts. The deserialization is determined by the request headers. In this case, Spring will see it is JSON and will automagically use Jackson JSON to try and deserialize the payload to the correct object type.
Note that I return a list of Contact objects. ExtJS is expecting the return value to be a list of the same objects, post-save, with the id property set. It assumes these are in the same order that was sent, so do not shuffle the order around.
Setting listful to true in the Writer is what allows us to configure this method to accept an array of Contact objects. Even if there is only one Record coming from the Ext.data.Writer, it will be wrapped in a JSON array and deserialized into an array of Contact objects.
Now what about the birthdate property? Again, I use a Jackson JSON annotation to configure what field gets read (“dob” in this case), and how that field gets turned back in to a java.util.Date instance.
My ExtDateDeserializer class does the opposite of the ExtDateSerializer class. It uses a DateFormat to parse the string in the JSON property for dob back into a java.util.Date.
So lets try to create a new Contact and save it. Here’s the console output:
This is where we get to that “incorrect” thingy I mentioned above. The default Writer will attempt to serialize this save() request like this:
So the Writer is sending a JSON object, which contains a property called “data” which contains the array of new App.Contact records we recreated. The problem is that Spring and Jackson are looking for a simple JSON array that contains the new App.Contact records. So we need to customize the Writer to make this work right. Here is the custom Writer implementation:
I override the render method of the default Writer to directly output the JSON array of Records, and not put the wrapper object around it. Using this SpringWriter instead of the default Writer results in a payload like this:
Notice there is no longer the wrapper. When we run the console code again, we get a successful save:
So that covers reading the list of Contacts and adding a new Contact. Again, the code is available on GitHub so you can dig in to it. I’ll follow-up with another post on the PUT (update) and DELETE methods, along with wiring this in to some widgets.
The Shift
I’ve added four developers to my team in the past month or so. Each got a brand new Dell workstation to configure as they liked. All chose to use Eclipse Helios over the MyEclipse IDE licenses the company had purchased. One chose to use VirtualBox and Kubuntu as his development OS. The most surprising thing was the choice of browsers: all but one are running Chrome as their primary browser.
I remember the days when Firefox was king for geeks. If you were doing web development, it was a must have tool. But those days are long dead. I ditched Firefox around the end of last year and haven’t looked back. And apparently I’m not alone. Chrome is now king for software developers, which does not bode well for Firefox. I’ll always appreciate Firefox for pushing innovation forward prior to the currently-waging Web 2.0 Browser Wars, but I suspect it is headed the way of Netscape Navigator.
Revenge of the Browser
Last weekend I attended the awesome Texas Javascript conference down in Austin, TX. This was probably the best geek conference I’ve been too. It made the early Rails conference look downright corporate. TXJS had awesome parties sponsored by Google and Facebook, the top names in JavaScript for speakers, and an open bar with mimosas for breakfast. This sets the bar pretty high on the geek awesomeness scale.
One of the most interesting discussions at the conference revolved around server-side JavaScript. Some very clever programmers have taken the V8 JavaScript runtime from Chrome, wrapped it with a library and pushed it out as a runtime for executing JS scripts on the server. The project is called NodeJS and it already has a pretty rich plugin environment around it. The implication is you can actually write a high-performance server-side application in JavaScript.
The trend for the past several years has been for the server-side programming languages to hide the JavaScript from developers. Both Rails and GWT approach things with a “use our language to do it all”. There is obviously value in this approach for people who don’t know JavaScript, but NodeJS suddenly flips that model on its ear.
The NodeJS story is “you use JavaScript already in the browser, so why not use the same skills on the server”. We now have a programming paradigm established at the browser that is pushing in to the lower tiers, rather than the lower tiers pushing out to the web. NodeJS has potential to obsolete a lot of what we think of as server-side development. Both Yahoo and ExtJS have projects in the works that use NodeJS as the backend, and I bet Google must have something going too.
NodeJS is basically the new Ruby. Keep an eye on what the cool kids start doing with it, and give it a try yourself. We’ll be seeing a lot more of it in the future.














