Archive for the ‘Development’ Category

Better error messages (Part 2)

Friday, March 19th, 2010

…Continued from part 1

In part 1, I scolded you for showing error messages to users.  I suppose I should ‘fess up though and just admit that I’ve shown my share of error messages over the years!  The more I consider the problem though, the more I think that error messages are a bit of a lazy way out. 

In this part, let’s get to a more practical level and talk about when it might seem important to show messages.  Hopefully we can find ways to avoid most of them.  There may well be other classes of messages that seem to require message boxes, but I’ll start with these. 

Reasons to show a dialog:

  1. Fatal error such as an unhandled exception
  2. Environment problem like file missing, bad permissions, hardware disconnected
  3. Transient outage (network, file server, database)
  4. The user must take action (user mistake, conflict with existing record)
  5. Warning/info message like update available

Fatal errors

On the surface this might seem like a no-brainer.  If you catch an unhandled exception in your Application object, then there just isn’t much that you can do about it.  Clearly, the ideal would be to avoid it, but it’s too late.  On the other hand, this is very valuable information.  This is definitely when you want your users to let you know so you can prevent it from happening again.  Remember though, that your user clicked OK, the dialog disappeared, and then the whole app went away.  Totally unexpected!

If the user can restart the app and keep going, then you probably won’t ever hear about it.  Sometime, over lunch, you might hear people make a mention of “that one” problem that happens a few times each week.  Don’t bother getting annoyed that no one reported it.  Code defensively!

If you can send that exception, the current record, any temp files, or anything else that would be useful, then you’ll be in much better shape.  Write the data to a tracker database, open a help desk ticket, whatever you need to do.  Rather than trying to reproduce an error that might happen once in a thousand times, this give you hard data from the time that it did happen.

Environment problems

These can be tricky.  If a file is missing or has the wrong permissions then something important just isn’t going to happen.  If hardware is disconnected, then your bar code scanner will be useless.  The good thing about most of these errors is that you can check for the condition before anything goes wrong.

If hardware is missing, display a message (I never said dialogs are completely forbidden!).  The trick is to do the work on the user’s behalf as much as possible.  The user will need to reconnect the device, but your code can check periodically and “unlock” the application when it appears.  After all, if it’s required, then clicking OK doesn’t serve any purpose unless the device is back anyway.

You can check for files to exist or even read-write permissions before writing.  Instead of a generic unhandled exception since “that file won’t ever be set to read-only” just expect it.  Log and send the error, then let the user know that the application isn’t useable without help desk intervention.  The worst thing is for the user to get through four screens of data entry just to lose everything due to an “impossible error.”  Make it work every time for your users.  You’ll have a better reputation and better information about what needs attention.

Outage

Databases stop responding.  Network links go down.  File servers get rebooted during production hours.  There isn’t much that you can do about them, but you pretty much know that the issue won’t last forever.  Let the user know that there is an outage, and make it clear that retrying is happening automatically.  Users hate “please retry.”  They already attempted it and it failed.  They are starting out annoyed and this won’t help.

Required action

Clearly there are situations where you can’t do anything for the user.  Is a required field missing?  Did another user update the same record and cause a conflict?  I hate to admit it, but here’s a situation that can’t be avoided.  At the same time though, you can do a better job with it.  Is a field blank or formatted wrong?  Jump to the field and flash a bright red outline around it.  Did the update cause a conflict?  Create a region above or below your contents that only appears with critical information.  Just like a web application will often have an error message area, there’s no reason why a desktop application can’t do the same thing.  A dialog gets dismissed and forgotten.  Show the message until the update is successful so the user can actually benefit from the information.

Warning/Info messages

Now these are definitely the bane of any user.  A message that says “record saved” is just a stupid impediment to the work flow.  Flash an indicator somewhere, show a non-modal notification (balloon dialog), or use a status bar in the application.  Just don’t interrupt for something that has no business interrupting.  The user only cares when something goes wrong – otherwise stay out of the way!

Continued in part 3…

Better error messages (Part 3)

Friday, March 12th, 2010

…continued from Part 2

So by now your applications are awesome!  You are winning industry awards, your users want you, and developers want to be you.  Things couldn’t be better!  Well, baby steps are good anyway…

There are two main lessons to take away from this rant article:

Lesson 1: Don’t leave it to the user

If the help desk needs information then applications need to take care of that automatically.  Just like Windows Error Reporting, applications need to submit crash data automatically if it matters.  The user is using software for one reason: to get work done.  Anything that gets in the way of that is a failure.  If you need to break flow for a dialog it had better be a critical error.  If it’s recoverable, then it’s not the user’s business.  Deal with it and leave the user alone!

Lesson 2: Recover automatically

If you have an I/O error, try again.  Delay if you need to so you don’t overload systems, but don’t make the user think about it.  If your application needs to crash, send a crash dump and then trigger a restart.  Windows has a great feature called Application Recovery and Restart where you have a chance to clean up from before the crash and recover pretty quickly.  It takes a little plumbing work but it’s worth it.

Lesson 3: Present information that’s actually useful

Don’t interrupt the user.  If you think you need to, think it through again.  If you still need to, make it painless as possible.  Don’t make the user remember things – just give them something relevant to complete their task.

 

Now that you know what not to do, here are few thoughts on better error handling.  It may or may not work in your application, but hopefully it will inspire more painless errors:

Solution 1: Dashboard

I’m guessing someone is already doing this, but nothing that I use.  Most applications, certainly LOB systems, have certain dependencies: network, file server, LOB system, database.  Create a bar across on one your application’s borders to indicate the state of these dependencies.  A green means good, red means bad.  A flash means a change to error.  When the LOB system goes red, that implies that something in the background detected a problem.  Hopefully it hasn’t even affected the user yet.  If they care, they can click the indicator to see details (tooltip or maybe even modal since the user initiated it).  With such a feature they will have warm fuzzies when things are green, and know who to blame when they see red (see what I did there?).

Solution 2: Interrupt Sparingly

Show modal “working” dialogs only if the user absolutely cannot work while something is resolved.  Indicate that the app is retrying.  If the user can work in part of the system but not another, then disable links to that part of the system until it’s resolved, and retry in the background to know when it’s resolved.  Take it out of the user’s hands.

Solution 3: Queued updates

Try to avoid real-time system updates whenever possible.  Queue up all updates.  In normal circumstances they will be immediately processed, but when problems arise they will seamlessly be managed.  Write queued data to disk to resume after problems.  Consider if updates should “expire” if in queue too long.  Discreetly display the number of pending updates to user.  This won’t work everywhere, but is ideal in a data-entry system.  This also has the side benefit of cleanly breaking blocking operations from the user interface.

Solution 4: Fatal errors

Certainly you will need to interrupt the user sometimes.  If you are expecting a license file and it isn’t there, or a critical DLL is missing all of a sudden, then there’s nothing that you can do about it.  You’ll need to stop the user.  This is the one situation that the user must be given a message.  The key is to make it short and to the point.  As little boilerplate as possible.  “The application is not configured properly.  A message has been sent to the help desk.  The application will now exit.”

 

There is no magic bullet, but you can make things better.  You can reduce messages – instead of hourly or daily occurrences, maybe they become weekly.  When errors do occur, they will hopefully stand out more.  Maybe then, users will notice messages.  Of course, if you do good enough jobs, you’ll already be fixing the issue by the time they report it!

Better error messages (Part 1)

Friday, March 5th, 2010

There was a very interesting discussion on Slashdot the other day about writing good, memorable error messages.  The question was basically: how do you get the user’s attention so they will remember the error instead of blindly clicking OK to get past it?  Developers are tired of getting a call saying that an app isn’t working, but no more details.  Worse still, users complain without the specifics, somehow thinking that saying “it keeps crashing” will help.

What it seems to come down to is that users are fairly immune to error messages.  They often won’t actually see a message in front of them since they are conditioned to ignore them.  Basically, if you are interrupting your users they will be annoyed and simply dismiss the message so they can keep going.  It’s pretty common to hear “you need to click OK twice when you save – I don’t know why.”  As developers we want to scream “read the message!”  We wouldn’t show a message if it wasn’t important.

But is that really true?  Let’s think about that a bit.  If an exception occurs and we display a message box what do we hope to gain by it?  The user doesn’t really care about what happened.  Either you work around the error, or the user needs to stop everything while something resolves itself (e.g. network outage).

The worst thing to do is to ask a user for an error message when they call the help desk.  The error will already be gone at that point unless it keeps popping up.  Remember that the first instinctive action was to dismiss the dialog.  The user doesn’t want to call the help desk.  The user doesn’t have time to call the help desk!  The automatic response is to click OK and try again.  Telling a user to reproduce an error is also a sure way to cause upset!

The Slashdot discussion mentioned creative ideas like using colors/shapes/images.  Perhaps the user would be able to say “it was the blue circle error” or “it was the dancing penguins” easier than “it was error #0800BADC: File permission error.”  The consensus, however, was that such solutions didn’t really help.  To the extent that a user will even remember such a message, this doesn’t convey any specific information.  A red square might signify file access error, but without a path and specific error how does that help in troubleshooting?

The bottom line seems to be that error messages are a losing proposition.  You need to do everything in your power to prevent error conditions from blocking the user.  Obviously, simply avoiding errors isn’t possible (no matter what you might tell your clients!).  Instead, you may need to be creative about dealing with unexpected issues.

Continued in part 2…

Link: http://ask.slashdot.org/story/10/03/01/132219/How-Do-You-Get-Users-To-Read-Error-Messages

Multithreading for the future

Sunday, February 28th, 2010

I haven’t talked about multithreading in some time but it’s even more important now than in the past.  Even some laptops are coming with quad cores now so you really need to be able to take advantage of them.  If you do nothing, then a computer will probably still see some better performance since several single-threaded applications can run concurrently, but if your application freezes up when it attempts to download a file or perform calculations then you’re going to look bad.

.NET 4 introduces some great parallel features.  You can create tasks that perform work and provide relatively easy synchronization.  They are lighter than threads since they are pooled and the API is easy.  As an abstraction over tasks is Parallel LINQ extensions.  You can do some amazing stuff by just adding .AsParallel() to a collection in your query.  This signifies that the collection can be split across threads, with the results joined back together at the end.  It’s super easy to do in most cases, and really provides a noticeable benefit.  If you need to provide hints for better performance then you can, but in many cases the defaults will do just fine.

Just working with existing libraries to manipulate data across multiple threads is useful though too, as plenty of legacy code won’t have access to new extensions. Understanding and using semaphors, locks, mutexes, wait handles, and even timers is invaluable.  Learn to synchronize code.  You should be able to start some work, and then notify another part of your code when it should proceed.

You need to really create a solid separation of data state from presentation – in other words, your UI should query the data.  State display needs to be a snapshot-in-time, not based on showing on-demand data from events.  You can either periodically check your state and update the UI, or take change events and dispatch them to a UI thread (as a window message) for deferred updates.  Once the window message is processed, you’ll be on the right thread and can show the new state, recent log messages, or updated status.

When a button is clicked, the event handler needs to do as little as possible.  Never perform an actual action directly from the handler.  Rather, start a background thread or task to do some work.  When the work completes, it can notify the UI, which in turn can be dispatched to the message queue.  Finally, the results can be displayed without ever causing the user to wait.

I use Picasa for photo management.  The programmers made a bad assumption that file access would be instantaneous.  You can never assume zero latency!  Even opening a file can freeze the UI when performed in an event handler.  How?  Imagine if you assume that a file is 120kb (and your testing reflects this) but the user is opening an uncompressed 25MB file.  What if the files are located on a network share?  Assumptions will always come back to bite you.  If you just assume that everything will be worst case and design your UI around that, then you’ll be fine.  As soon as you decide that a “normal” environment is close to your own, then you’ll make bad choices and performance will suffer.

Passionate programmers

Saturday, February 27th, 2010

Do you like to program?  I mean really like to program?  Apparently you aren’t in the minority if you said “no” to that question.  I got into an interesting discussion about hiring good programmers last week and the consensus was that the best programmers were the ones with a passion for it.  This isn’t all that revolutionary to those of us who are passionate about it, but perhaps you disagree.  Isn’t programming just about converting needs into code?  It seems as dry as materials engineering on the surface (no offense to materials engineers out there), and yet discussions about languages, algorithms, and design patterns bring about something akin to a holy war.  Somehow I doubt that materials engineers end up flaming each other over the general advantages of various alloys – independent of any specific application!

It’s always been amazing to me how polarizing computer science issues can become.  Though everyone agrees (in a general sense anyway) that the tools and language are dependent on the scenario, once you start talking specifics, no one can agree on anything!  Though this isn’t productive most of the time, it does certainly demonstrate a passion unmatched in many fields.  People who are really into programming get really passionate about every detail.  Conversely, people who tend to code as a job and nothing more don’t care about the details – they are just tools to get the work done.

Why is one programmer “better” than another?  Maybe that’s too strong a way to phrase it.  Why would I be more interested in hiring the passionate developer?  Well, even though I might need to face heated discussions about design and implementation from time to time, I would know that the person was putting a lot into the effort.  Hours spent at home learning new technologies, time spent at work to eek out every bit of performance and efficiency, and the attitude that the final work reflects personally on the code all mean that a passionate developer is more likely to create good code.  On the other hand, I’ve worked with developers who just like to argue because their knowledge base is narrow and they want to keep designs in their comfort zone.  We need to eliminate this too!

Thus, the programmers that I would look for would be passionate about the field, and their passion would lead them to explore new features and tools to provide more options.  A passionate programmer will consider coding more than just a job and will keep up to date as technology changes.  Does this mean that “day job” programmers can’t write great software, or that passionate programmers don’t have a life?  Not at all.  They aren’t mutually exclusive attributes.  Just like any field though, it’s passion that usually leads to the best solutions.

Necessity

Sunday, January 31st, 2010

This is somewhat of a philosophical post, so bear with me here!  I find the application development process itself to be really interesting and so it’s something that I think about at times.  As a person who writes samples, articles, demos, and other content for  products, it’s pretty common for me to actually need to come up with the idea for the software – not just the software itself.  This is backwards from most software development.

Think about it – an enterprise developer creates software that speeds up or reduces errors for the company’s people.  A “dot com” developer creates a site that addresses some need in order to bring in people for advertising, subscriptions, or what have you.  A hobbyist developer creates a solution to a problem that s/he is having – a magazine collector wants a tool to assist with the collection, and a musician might want a tool for keeping track of gigs.  The bottom line is, as the old proverb goes, necessity is the mother of invention.

Not so with people like me!  The necessity in this case is the need to create interest and provide help with a product or technology.  I end up racking my brain for a scenario that is somewhat realistic and demonstrates the necessary attributes of the product.

As an example, let’s say that I need to come up with a sample of the new file drag-and-drop feature in Silverlight 4.  Drag and drop is nothing new, but it’s new to Silverlight.  I could create an almost “Hello World” style of sample that just exposed a panel, and when a file was dropped it would display the filename.  That’s a pretty basic sample, and a pretty common way to demonstrate something – just create something quick and dirty that shows it.  It’s not very compelling though, and in the end it doesn’t create much more benefit that a paragraph or two of SDK documentation would provide.  The key is to demonstrate real benefit.

Part of a sample is showing how the code works, but an arguably bigger part is showing why you would want it to work that way.  A drag-and-drop panel satisfies the former requirement, but not the latter.  A better example would be the classic file uploader applet.  As you drag files, they get added to a queue and then upload in the background.  This is a clear benefit to a form submission method of uploading files.  It makes sense, it’s quickly graspable, and with some tweaking could probably even be adapted for actual use on a web site.

There is a balance though.  A sample shouldn’t have so much going on that the demonstrated technology is lost.  It should be easy to factor out the rest and focus on the feature of interest.  In the file uploader example, the queuing and uploading needs to be in separate classes so the work of accepting a dropped file is obvious, clear, and adaptable for other needs.

A sample, demonstration, or article that includes code that meets these criteria is considered a success by me.  Doing this on a project with multiple samples, and over multiple projects can be quite a challenge.  It’s very rewarding to get it right though!

Building Communities

Saturday, January 30th, 2010

At Aeshen, we are often tasked with figuring out how to build up a community around a given product or technology.  This is an important step in assuring success.  Building up a community around something can be the difference between being a blip on the radar and taking the world by storm.  Building up a community isn’t easy though, and it requires careful intervention from a product’s caretakers in order to see it through.

One way to get the ball rolling is to get the word out as early as possible.  This is a great first step to discover the need.  Early blog posts, articles, and references can really make a difference.  Once people are expecting a technology, they start to really think about how it would change things, and there will be a pent-up demand for it to be released as quickly as possible.

Once people are talking about it, it’s important to get them together.  Creating blogs with commenting and hosting chats can gauge interest further, but also enable people to share their thoughts.  At this point, no one can do much more than conjecture, but as more blog posts and other communications emerge, the discussion will become more focused.

Releasing videos of products or interviews with designers/architects can also get people more interested as they are getting a more in-depth look as what they can expect.

When it’s time to release the technology, it’s vital to have as much content available as possible from day one.  Everyone loves to download that new library, but API documentation is only going to take them so far.  Creating samples is really a requirement.  Creating hands-on-lab documents with detailed explanation of steps get people thinking in the right mindset for getting the most out of it.

With all of these people working with samples and labs, having forums is really important.  This is where people can shine by showing off their knowledge to others and learning together.  Give people points for participating, allow discussions to be flagged as good or bad, and use a layout that allows good content to float to the top easily.  All of this gets people talking, learning, and ultimately using the technology.

Finally, a good community must be nurtured.  Make sure that you have official responses from time to time, release additional samples, talk about upcoming versions, allow users to vote on bug fixes and features.  All of this will make the difference between a few people trying something out, and a community of people passionately evangelizing your work with you.

LINQ to SQL – Part 2

Saturday, January 30th, 2010

In my last post I talked about how LINQ to SQL greatly simplifies working with database tables in your code.  No longer do you need to sprinkle SQL throughout your code and iterate through results to create business objects.  LINQ handles it all for you so you can concentrate on what to do with those objects.

What’s amazing is how well LINQ to SQL’s query generator works.  If you have started using LINQ to Objects, you know how great it is to find specific objects in a collection, to sort, and even create secondary objects from data.  All of this is amazing, but extension methods make it fairly easy to understand what’s happening behind the scenes.  When you work with LINQ to SQL, you include the use of a DataContext object.  This is where the magic happens.

A DataContext encompasses details about how the database relates to the business objects.  This is where you declare that a Person object is an instance of a row from the Persons database table, and the object properties relate to columns.  From there, all CRUD operations can be easily generated.

Simple operations are easy enough, but when you start layering on operations like grouping, Take(), and Skip(), the query  generation really shines.  The DataContext creates an expression tree based on your query, and then executes it when used.  This is called deferred execution and is an important distinction.  Merely assigning a query to a variable, like this:

var people = from p in DC.People where FirstName == “John” select p;

does not result in any SQL queries being sent.  It’s not until you work with the collection that data is retrieved.  This makes it possible to reuse a query throughout your code and always have fresh data.  If you want to cache your results, simply call ToList() on the query, and it will execute right there.  Basically, as long as it’s an enumerable it will execute on each enumeration.  Once converted to a list, the results are static.

There are many great resources out there to learn more about LINQ to SQL.  Fire up AdventureWorks, Northwind, or your favorite sample data and start trying it out!

LINQ to SQL

Monday, January 25th, 2010

If you’re still writing SQL queries in code, you are really missing out.  Writing queries by hand is always error-prone and can lead to long debugging sessions.  As a data persistence model, LINQ to SQL is easy to use and really makes a difference in the quality of code that you write.

After using the LINQ Designer, you have a model of your tables in a standard looking Entity Relationship Diagram.  From there though, your code can query your database by simply working with objects.  If you like LINQ to Objects for working with in-memory collections, then you are most of the way there.

The cool thing about it is how the query generator works behind the scenes.  When you create a query using object calls, a T-SQL statement takes form with all of the necessary pieces in place.  It parameterizes, adds sub-queries , inserts ROW_NUMBER syntax , and does all of this without you needing to think about how it fits together on the database side.

What if policy prevents you from sending ad-hoc queries to the database though?  No problem!  LINQ to SQL lets you specify stored procedures to call for all CRUD operations, then stored procedures to call for business-specific needs.  You lose the query generation coolness at that point, but you retain the ability to work with database data as local objects without tedious work to create objects from result sets.

The objects returned from your LINQ operations provide fully-typed access to your data along with nearly effortless updates and inserts to the database.  You can focus on what to do with the objects, such as binding to user interface elements, rather than spending time integrating data access code.  Let your database team create the queries or stored procedures, then assign them to the objects with ease!

In my next post, I’ll talk more about the mechanics of specifying database hints to the LINQ to SQL designer, and how to make effective use of it all from code.

ASP.NET

Thursday, December 31st, 2009

I’ve gotten a lot done this past week building a web site.  From the master page, to the web forms, to user controls, I’ve been working hard to create a layout that facilitates changes and is easy to reuse.  The scripts are saved in separate JavaScript (ECMAScript) files, CSS is pulled out in most places rather than in-line, and I’m using jQuery to wire up behaviors to elements.

Some important tips and tricks:

  • Declare a ScriptManager in the MasterPage.  Only use ScriptManagerProxy objects in pages and controls.  This ensures that you will be able to attach scripts at any level without that warning about having more than one ScriptManager object.
  • Create separate JavaScript files for each page and control, then reference them using the ScriptManagerProxy on the object.  Name the script files based on the object name for convienience.
  • If you are using jQuery, make sure that you download the Visual Studio documentation file.  This vsdoc/vsdoc2 file must be place at the same location as the main library file.  Do not reference the vsdoc file from anywhere.  Just make sure that it has the same file name as the main file with the “–vsdoc” added (including version number or anything else).
  • In external script files, Visual Studio has no context for other script files that are loaded in the object.  To get around this, reference the file like this:
    /// <reference path=”jquery-1.3.2.js”/>
    This does nothing at runtime, but gives you that wonderful Intellisense at code-time.
  • Use multiple style names on elements.  Unlike C#, Java, and other object-oriented languages, you can have multiple inheritance in CSS.  Some can affect layout, some behavior, and some will just end up being decorators to help you with jQuery selectors.
  • Databind wherever possible.  If there’s one thing that I’ve learned from WPF and Silverlight, working with ControlName.Text or ControlName.Value is no fun!  Learn how to do binding to simplify your life.
  • If possible, leave the design work to someone else!  Focus on div elements anywhere that you can.  Drop in a CSS sheet from someone else and markup the div’s with class names and let that be taken care of.  It may not work out that cleanly, but ideally, do as little layout and design as you can and get the functional bits working.  Keep design out of it as long as possible.