Friday, May 05, 2006

UI Design: When do you save?


How do developers save?? I know I know, after reading some of the comments on UI Design: Edit then List vs List then Edit I learned that most developers believe that the UI Design is a user concern, not a developer concern (build the UI as the User wants it, not as the developer wants it)... I have been wondering...

  • Do the users really know what they want?
  • Do the users really appreciate some of the internal behaviors the UI provides?
  • Do all software projects have enough budget and type to make real usability test?
  • Do all customers pay an amount of money for a project that justifies the extra effort of building a well designed UI?
  • Do you as a developer have a framework that make all this issues moot and for you is so extremely easy to build a good UI that you always built it in the absolute best way?

Lets take, for example the "Save" or "Cancel" button in a typical CRUD application, and lets say the UI is build following List then Edit:

  • The user search all customers named "John"
  • The user selects the first one from the list
  • The user clicks the edit button on the tool-bar (in the List window)
  • The Edit window appears, the user modifies everything (from some fields, to complex to many, to one, many to many and many to many relationships) and then...
    • The user clicks "save" because he is happy with his changes
    • The user clicks "cancel" because he is not happy with his changes.

Now... a well behaved system, shouldn't write anything into the database until the "save" button is clicked (regardless of the complexity of the "edit customers" UI) and a well designed persistence API should make it as easy as "editingContext.Rollback()" to achieve that effect... and, if we weren't editing an customer, and from a performance perspective, if as a result of the editing of customer we created new "detail" objects(or rows) and we decided to cancel the operation, the server shouldn't even be aware that we created those objects, and then "roll-backed" its existence.

But the questions now is:

  • Do we all always check that nothing is written on the database until we click "save"? and "Does the user care?"

I know I always try to check that if and only if the save button is clicked I save... but I have met lots of other developers that do not care... if for example, they have to add new addresses to the customer they write the new addresses into the database the moment they create them (from inside the edit customer ui!) and after the "cancel" button is clicked, this to many relationship is not rollbacked... they just don't care...

Now... I have to admit that I have done this sometimes (when in a extreme hurry to deliver a new form) , and "i feel" like it is enough if I add a message box warning (of those the user never reads) saying "if you add a new address all your changes will be committed to the database" ... the user, as always, just dismisses the warning and proceeds to add addresses... and perhaps click cancel later... nevertheless as soon as I have time, I fix the form so that it only saves when the save button is clicked... (and sometimes, with complex nested UIs that is a pretty hard job)

But... the thing is that I have seen lots of systems built with the idea "if you write it on the screen, and you do as much as click any button your changes will be saved" I have seen it specially in web based systems, but also in smartclients... and I have had the opportunity to hear all kinds of complains of this systems, and I have even replaced some of them with "only if you click save you save" systems... but I have never heard a single user saying "it is nice that the cancel button really works now" or "i hated the previous system because I clicked cancel and it saved my changes" but... strangely I have heard some of them complaining "I added 50 addresses to a customer, and then by mistake i clicked cancel, and then by mistake again I answered "yes" to the question "Are you sure you want to cancel your changes" and my changes were lost!!!!

But that has been my experience... maybe you do know a user that appreciates a consistent behavior in the "save" and "cancel" buttons...

How do you decide the transactional UI boundaries of your system? Do you really ask the user "do you want the cancel button" to really work? Do you always have the time to build 2 o 3 different UI prototypes and really test usability? Do your users really appreciate the extra 2 o 3 days that may take you to build a transactionally consistent UI? or the they prefer an UI that is built faster and if they made any mistakes, they "edit again" and rollback the mistakes manually (and they are happy with that behavior)? have you ever received a complain from a user saying "i want a cancel button that really works"? Do you implement cancel by calling an API similar to "editingContext.Rollback()" or do you cancel in "a custom way" (by explicitly deleting changes already made to the database) ? do you offer real "save" and "cancel" buttons even in your web based applications?

1 comment:

ChristianAcca said...

Nice couple of posts.

I've read similar discussions. You may want to have a look at NPersist (now part of the Puzzle.Net framework) that seems to propose an an elegant way of handling the cancel dilemma Personally I haven't actually used this ORM, but I did find the idea extremely interesting!

Here's a snippet from a blog post from the guy that wrote the ORM explaining the idea:

The idea is simple: You have a root context/cache which is your long-lived cache that lives as long as your WinForms app is running. Then when you open up an edit employee screen, you instantiate a new context passing the root context to the constructor, and then ask for an employee object from the new “leaf” context passing the employee from the root context as the “id” parameter to leafContext.GetObjectById();

IContext leafContext = new Context(rootContext);
Employee leafEmployee = leafContext.GetObjectById(rootEmployee, typeof(Employee));

//go on to data bind to leafEmployee

You then get a new Employee object that belongs to your leaf cache and has all its values copied from the original employee object. You go on to data bind to the leaf employee. If the user presses OK, you call leafContext.Commit() and the values will be copied back from the leaf employee to the root employee, and the root context is persisted saving the values back to the database. If the user presses Cancel, you just throw the leaf context and the leaf employee away.

You can do this recursively. Say that from the edit employee form you can open another form (to edit the project the employee is working on or something). This form would create its own new leaf context, using the leaf context from the previous form as its root context. Thus this form too could sport a nice Cancel button and still use data binding. If the user presses Cancel in the edit project form, everything back in the employee form is just the way it was left, but if the user presses OK, anything in the employee form that might be affected by the project’s modifications would now be updated."