## Those messages are for other developers Those messages are **expected to be read by developers** to help them debug the application. This can take two forms: - Active debugging. You're actually running a debugger while writing code and trying to figure out what happens. In this context, a helpful exception will guide you by making it easy to understand what's going wrong, or eventually suggesting a workaround (although this is optional). - Passive debugging. The code runs in production and fails. The exception is logged, but you only get the message and the stack trace. In this context, a helpful exception message will help you quickly localize the bug. Since those messages are often logged, it's also means that you shouldn't include sensitive information there (such as private keys or passwords, even if it could be useful to debug the app). For instance, `IOSecurityException` type of an exception thrown when writing a file is not very explicit about the problem: is it because we don't have permissions to access a file? Or maybe we can read it, but not write? Or maybe the file doesn't exist and we don't have permissions to create files there? Or maybe it's locked (hopefully, the type of the exception will be different in this case, but in practice, types can sometimes be cryptic). Or maybe Code Access Security prevents us from doing any I/O operation? Instead: IOSecurityException: the file was found but the permission to read its contents was denied. is much more explicit. Here, we immediately know that permissions on the directory are set correctly (otherwise, we won't be able to know that the file exists), but permissions at file level are problematic. This also means that **if you cannot provide any additional information which is not already in the type of the exception, you can keep the message empty.** `DivisionByZeroException` is a good example where the message is redundant. On the other hand, the fact that most languages let you throw an exception without specifying its message is done for a different reason: either because the default message is already available, or because it will be generated *later* if needed (and the generation of this message is enclosed within the exception type, which makes perfect sense, OOPly speaking). Note that for technical (often performance) reasons, some messages end up being much more cryptic than they should be. .NET's `NullReferenceException`: > Object reference not set to an instance of an object. is an excellent example of a message which is not helpful. A helpful message would be: > Object reference `product` not set to an instance of an object when called in `product.Price`. ## Those messages are not for end users! **End users are not expected to see exception messages. Never.** Although some developers end up showing those messages to the users, they ensure by that poor user experience and frustration. Messages such as: > Object reference not set to an instance of an object. mean absolutely nothing to an end user, and should be avoided at all costs. The worst case scenario is to have a global try/catch which throws the exception to the user and exits the app. An application which cares about its users: - Handles exceptions in the first place. Most ones can be handled without disturbing the user. Network is down? Why not waiting for a few seconds and try again? - Prevents a user from leading the application to an exceptional case. If you ask the user to enter two numbers and divide the first one by the second one, why would you let the user to enter zero in the second case in order to *blame* him a few seconds later? What about highlighting the text box in red (with a helpful tool tip telling that the number should be different than zero) and disabling the validation button until the field remains red? - Invites a user to perform an action in a form which is not an error. There are no enough permissions to access a file? Why not asking the user to grant administrative permissions, or pick a different file? - If nothing else works, shows a helpful, friendly error which is specifically written to reduce user's frustration, help the user to understand what went wrong and eventually solve the problem, and also help him prevent the error in the future (when applicable). ## Those messages are not for parsing Exception messages are **not expected to be parsed** or used programmatically either. If you think that additional information can be needed by the caller, include it in the exception side by side with the message. This is important, because the message is subject to change without notice. Type is a part of the interface, but the message is not: **never rely on it for exception handling.** Imagine the exception message: > Connecting to the caching sever timed out after waiting for 500 ms. Either increase the timeout or check the performance monitoring to identify a drop in server performance. The average wait time for caching server was 6 ms. for the last month, 4 ms. for the last week and 377 ms. for the last hour. You want to extract the “500”, “6”, “4” and “377” values. Think a bit about the approach you will use to do the parsing, and only then continue reading. You have the idea? Great. Now, the original developer discovered a typo: Connecting to the caching sever timed out after waiting should be: ↓ Connecting to the caching server timed out after waiting Moreover, the developer considers that month/week/1 hour are not particularly relevant, so he also does an additional change: > The average wait time for caching server was 6 ms. for the last month, 5 ms. **for the last 24 hours** and 377 ms. for the last hour. What happens with your parsing? Instead of parsing, you could be using exception properties (which can contain whatever one wants, as soon as the data can be serialized): <!-- language: lang-js --> { message: "Connecting to the caching...", properties: { "timeout": 500, "statistics": [ { "timespan": 1, "unit": "month", "average-timeout": 6 }, { "timespan": 7, "unit": "day", "average-timeout": 4 }, { "timespan": 1, "unit": "hour", "average-timeout": 377 }, ] } } How easy is to use this data now? Sometimes (such as within .NET), the message can even be translated into user's language (IMHO, translating those messages is absolutely wrong, since any developer is expected to be able to read in English). Parsing such messages is close to impossible.