Wednesday, April 23, 2008

Curious Design Choice

In eclipse, in the java editor, Ctrl-S (save) is RIGHT NEXT to Ctrl-D (delete line).

I understand WHY they are, but it's a bad design all the same. Often, if you're not accurate, or you're using the typical crap laptop keyboard, one can hit both; in the wrong order this can be rather irritating at best, disastrous at worst.

Any other examples of this?

Friday, April 18, 2008

Creative Employment Agreements

I was chatting with a coworker today about some company issues, and I had offhandedly mentioned a thought I've had over the past few years; that being, putting something in your employment contract/offer letter/acceptance/etc. that wasn't already there.

In my case, had I remembered it when I joined this company; this is an old, old thought that I've never followed through on; I would have specified:

  • Any "team building" exercise FOR the sake of team building, I would be free to opt-out of.
  • I am not required to attend weekly status meetings.
  • I am not required to submit weekly status reports. I would of course couch both of these in terms of being perfectly happy to provide relevant status updates to my manager, just not in the "Management 101", Andersen Consulting style TPS reports and meetings.
  • Probably something about meetings. This is a little easier; one can just not accept invitations if it's not convenient, which I often do already.
Naturally the company would be perfectly within their rights to NOT hire me with these riders on the contract and I accept that. It just seems like these types of things would be as much or more easily negotiated than the standard pay or vacation time items.

Has anyone done anything like this? How'd it work out?

Thursday, April 17, 2008

What's A Good Error Message?

What makes a good error message? As developers, we certainly see a lot of them, and they are almost always the first indication that Something Bad (tm) has happened. So what makes a good one?

In order to answer that, it's probably best to illustrate what they are FOR. There are generally 2 classes of error message:
  1. Messages intended for users. These messages indicate that the USER has done something wrong. Typically bad input.
  2. Messages intended for the developers. These are TYPICALLY cries, bleats, or yelps for help to tell the programmer that something unexpected has happened.

Since this isn't "Adventures in Usering", I'll focus mainly on the latter.

So what makes a good error message? I've given this a bit of thought lately, and I think that a really good error message has the following 4 qualities:
  1. It tells what was expected.
  2. It tells what it actually got, and how or why that is different than what was expected.
  3. It tells how or why this might have happened.
  4. It gives some direction on how to fix the problem.

As an example of a good error message, let's look at some pro and counter examples.

The ultimate counter example of all 4 qualities can be seen here

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler

Awesome. It tells me, as a developer, absolutely nothing useful to find out what the heck happened, what was SUPPOSED to happen, where it happened, or what I'm supposed to do about it. This particular nugget occured while starting up an application server. Since it is java code, I was able to see the stack trace that led to it, so I had a very small clue as to where to start looking.

This is an example of a very common type of error message; the "I'm an error message" message. We've all seen these; they provide no useful information other than the fact an error occurred. A message announcing that an error occurred is obviated by the fact the message is there at all. I used to joke in college that I was going to write a compiler and to save message space, it would have one error message that said simply, "No". I didn't think so many developers would steal and stylize my idea, but apparently they have.

So what would have been better?

Tell me what was expected

In this case, this error was the result of a missing file that was needed during some startup code. So, tell me that.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml

NOW we're getting somewhere. Even with THIS bit of info, I might have an idea by putting together that there IS an error message, and that it's saying that it's expecting to read from a given file, that maybe something is wrong with that file. My years of experience might lead me to see if that file exists, its permissions are such that it can be read by the app, it looks "ok" (not zero length, the format matches what it probably should (xml), etc.)

Tell me what actually occurred

Now that we know what the app wanted, an indication of what differed from this expectation would be nice.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file was not found

Hey now, this looks promising. And spares me the checks I would have had to make if this tidbit were missing, as before. Too, it disambiguates from something like...

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file is not readable

Tell me how this happened

Unfortunately, this isn't always possible, and sometimes the first 2 bits of information are more than enough to get started. But when writing error messages, if you have any idea of how the error could have occurred, put it in the message.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file is not readable. This can occur if permissions are set incorrectly on the file or its directory. This happens often during an initial setup of the application, since this file is deployed separately from the application itself.

Be careful here, this might lead a developer or tester to the wrong conclusion. When writing error messages, if there are a litany of reasons an error might occur, I will often leave this step out since it would be too much to list them, and just listing some might cause one to not check the others.

Tell me how to fix it

This one can also be tricky, since it's often not known how to fix the problem, especially when the error message is first being coded. However, I've found that over time developers will tend to see a certain error and know what causes it. If possible, that's the time to go back and fix the message (if possible, and it often isn't). Or of course, sometimes an error can only be fixed in a limited number of ways. So, list them.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file is not readable. This can occur if permissions are set incorrectly on the file or its directory. This happens often during an initial setup of the application, since this file is deployed separately from the application itself. Check the permissions on /opt/apps/config/i18n.xml to ensure they are readable by the application.



Although I've gone a bit off the deep end on this particular example, if I'd had this information on this very real message (but somewhat obfuscated to protect the perpetrators of such heinousosity), it would have saved a lot of debugging time. In this particular case, the application reads a file that lists what OTHER files it should read, and it was one of those second level files that was missing. Because the error message was so vague, I had to step-debug into the code at that point, and check EACH LOOP ITERATION until I found the offending iteration and fix the file it couldn't find. This took the better part of a half hour, and it wasn't the first time, so I knew where to start. Two minutes by the original programmer would have saved me and coworkers of mine hours of debugging time.