Simplicity is Golden

Steve Krug said it …

Don’t make me think!



 What do the following companies have in common?

  • Apple
  • Microsoft
  • Amazon
  • Facebook
  • Google

Well, besides the fact that they make a lot of money; they followed this rule!  Apple made it easy to use a phone.  Microsoft made it easy to use a computer.  Amazon made it easy to buy books.  Facebook made it easy to connect with friends.  Google made it easy to search. 

They weren’t the first.  They were, at times, mocked for their approach.  Competitors boasted - More Features! - Prettier Pictures!


They made it simple to use their product. You could open Google and spend more time figuring out what you were trying to search for than how to search for it.

Think about games you have played.  Were they easy to learn?  Were they hard to master?  I’d say for every game I ever got “addicted” to, the answer was yes in both cases.  

But it goes bad…

Never forget where you come from…

Success has a habit of going to our heads.  We build something good, and then we want to make it better.  It is at this point that we most often forget about keeping it simple.  

Make it easy to use; but capable of much more.

(this is as-of 2/3/2012)

Take a look at Google.com in Chrome.
Now take a look at it in IE.

This is the classic example of forgetting what makes your product so great.

Simplicity

The old way: Menu links shown across the top of the page.

The “enhancement”: An image you have to hover over to view a menu which you can navigate from.

I don’t have to explain how it takes more steps to get to “News Search”.  But this is to the core of what making your site less-usable through enhancement is all about.

Lets make it better by enhancing the navigation

I’m still waiting for us to come up with an enhancement to the hyperlink.

A Guide to Sexy Exceptions in .NET

System.NullReferenceException: Object reference not set to an instance of an object.

Whether you are a rookie developer or a weathered code monkey, you have seen this exception at some point in your work.  Chances are, if you are the latter of the two, you have dealt with tracking the issue down and dealing with it.  My goal, is to make that better.

The pain is that this exception does not tell you more than “hey guy, something was null” - if your lucky and running code with debugging symbols, you get a line number.  But it is up to you figure out what is null, why it is null, and how to fix it.

Beyond the immediate remedy to your bug, it should become immediately apparent that you have an exception design issue. 

An exception design issue is when an exception thrown to a user does not provide immediate actionable information without further investigation.

Here is What I Think

As hinted to above, my opinion of a good error is one that tells you:

  • What happened.
  • Why it happened.
  • How (if) it can be fixed.

Take a simple form where you fill out some info.  You wouldn’t (I hope) show the user a message like:

Form is not complete

We can do better than that:

The value you provided for Field X is invalid and must conform to this format.

Why should exceptions be treated any differently?

Consumers of your application could be users.  They could be developers.  They could be hackers from Mars.  Just because the users are more savvy, does not mean they can telepathically debug your application.

Your goal should be to provide the best experience to all of your users, especially when your application fails. 

How About an Example

One of the best examples I like to use is around using appSetting values from a configuration file.  Assume the following:

  • We are looking for an appSetting value in our config file called “ApplicationName”
  • We expect the value to be a string, and not empty/null
  • We do not have any error trapping if the value is not there.
  • The config file does not contain the key “ApplicationName”

So, given this, if we fire up our application we should get an exception.  Most likely, we get a NullReferenceException.

Stop For a Moment

Remember who your users could be and put yourself in their shoes.  Without the source code, do they have any idea what really is happening and what to do to fix it? - NO!

The most they can possibly know is that somewhere, someone forgot to put a check for null values in place.

Lets Make This Better

If our code looks like this…

string appName = ConfigurationManager.AppSettings[“ApplicationName”].ToString()

We know that the .ToString() call is what is throwing our exception.
For sake of the demonstration, we will leave this line as-is.

try
{
     string appName = ConfigurationManager.AppSettings[“ApplicationName”].ToString()
}

catch(Exception)
{
     throw new Exception(“There was an error obtaining the ApplicationName from configuration.”);
}

Now What Do We Know?

We know WHAT has happened.  We don’t know WHY or HOW we can fix it yet.  So, we still need to make this better. 

WHY should tell the user the reason for the situation.

Lets tweak it…

catch(Exception) { throw; }

catch(NullReferenceException)

{

     throw new ConfigurationErrorsException(“There was an error reading ApplicationName config value; the setting was not found.”);

}

As you can see, I have done a couple things here to clarify the error that is thrown. 

  1. I have singled out the situation where a NullReferenceException is thrown.  Ignore the low-hanging fruit here, this is just for sake of the example.
  2. I have changed the exception type to a ConfigurationErrorsException.  If this code is referenced elsewhere, we have a way to distinguish this exception from others.

Completing the Picture

So, we have the WHAT and the WHY taken care of, now we have to tackle the HOW.  This can be the hardest part of the puzzle.

HOW should tell the user what they can do to fix the problem. 

The hard part about this is not overdoing it.  You don’t need 3 paragraphs of possible solutions.  When more than one solution could exist, give the user the most likely resolution as a possible fix.

Lets tweak it…

catch(Exception ex)

{

   throw new ConfigurationErrorsException(String.Format(“An unexpected error occurred when trying to read the ApplicationName setting from configuration.  {0}”, ex.Message), ex);

}

catch(NullReferenceException)

{

   throw new ConfigurationErrorsException(“There was an error reading ApplicationName config value; the setting was not found.  To resolve this, add an appSetting to your configuration with valid string value.  This value cannot be empty.”);

}

Now we are looking much better.  There are two keys here…

  1. We expanded the first catch to let the user know that something happened that we were not expecting.  We explain what was being done and what the unexpected event was.  At this point, it is all the information we have.
  2. We expanded on our second exception and explained that the user can resolve the issue by adding the missing setting.

This gives us a WHAT, WHY, and HOW

Summing It Up

Good exception design is something that can go a long ways towards improving the user experience with your application.  I realize there is quite a bit of low-hanging fruit in this post but I ask that you look past it and understand the concept I am trying to convey.

Further Reading

If you are more concerned with general practices with throwing exceptions, check out a few of these resources.

I will be following up to this at a later point with some other general practices I like to follow.

kick it on DotNetKicks.com

It’s a dirty seceret that much of what we admire in the design world is a byproduct not of ‘strategy’ but of common sense, taste, and luck. Some clients are too unnerved by ambiguity to accept this and create gargantuan superstructures of bullshit to provide a sense of security.
Michael Bierut
Performance = Feature
Jeff Atwood
IE9 - Good, Bad, Ugly

IE9 has been out for about a week now.  I wanted to jot down some of the things I like/dislike about it.

The Good

  • Performance

  • The interface

  • Tabs scale to to the space available

  • No surprises, despite the rendering/display issues

The Bad

  • Having to click + hold the back button to see a list of previous sites.  How am I supposed to know to do that as a user?

  • When you configure it to open new windows in tabs, you expect it to re-use the existing window when an outside program requests a page; IE seems to like to open lots of new windows, despite this.

The Ugly

  • When you configure it to open new windows in tabs, pop-up blocker will not work.  Case-in-point: go to accuweather.com and check weather for your area.  In many cases this should cause a “Netflix” popup.  Without the tab configuration, it is blocked by the popup blocked. 

  • Lots of rendering issues; the cycle continues.
Convert FormsIdentity To ClientFormsIdentity

Background
If you have been using Client Application Settings (CAS), like me, you are well aware that it is a great framework.  But like anything else, it has a few limitations.  In this case we are referring to an issue that you may encounter when working in a Single Sign-On (SSO) environment.

The issue materializes when you have an authenticated user that requests a page on your site where your Profile information is provided via CAS.  The reason this is an issue is that ASP.NET, when using Forms authentication, will populate the HttpContext.Current.User.Identity property with a FormsIdentity.  However, with CAS you are going to need a ClientFormsIdentity.  You are going to need to craft some magic to get that FormsIdentity into a ClientFormsIdentity and attached to Thread.CurrentPrincipal.

Read More

Resolving NullReferenceException with ClientApplicationServices / ProfileService

If you have been (or trying to) work with Client Application Services, you may have chased this issue like I did this morning.

The Setup
You are working with Client Application Services, specifically the Profile Service.  You have either added a new profile property or you are just trying to get synched up for the first time. You select Load Web Settings, you enter a valid username/password, it waits for a second and then you get this….

The Solution
The real culprit, in my opinnion, is a bug in the profile service which should at least fail a bit more gracefully.  You can resolve the error by updating (or adding) the following configuration section to your web.config … 

System.Web.Extensions/Scripting/webServices/profileService

Upon further inspection…

By default, no profile properties are available. To make a profile property available to a client application, add the property name to the readAccessProperties attribute of the profileService element. To enable a client application to update a profile property value, add the property name to the writeAccessProperties attribute.

So, armed with knowledge we can now add a coma delimited list of properties in the readAccessProperties attribute of the profileService configuration entry. 

<profileService enabled=”true” readAccessProperties=”FirstName,LastName,EmailAddress” />

Migrated to Tumblr tonight

Greatly impressed with how easy it was to migrate to tumblr this evening.