There are a certain set of states or operations within a running program that are not fatal, but are not completely correct or allowable either. I will refer to these as "warning" states, since one of the fairly reasonable things to do in these cases is offer a warning to ther user that they are doing something wrong. Unfortunately, many developers seem to interpret the concept of being fault-tolerant as being silent, meaning that if something is wrong, not only should you gracefully handle and recover from it, but no one should be the wiser.
It's the second part that I take issue with. If you don't publish some kind of message indicating that you have encountered an unexpected state but then handled it, the user will never know that anything was wrong. This is infinitely frustrating when debugging because the output of a "working fine" system will be identical to that of "one or more non-fatal things went wrong" system. I can give two recent examples from my own experience:
- I mentioned this in yesterday's post: HTML editing and layout is a classic example of silent failure. I can perfectly well understand the browser's desire to be fault-tolerant since in general the user is probably not especially tech-savvy and couldn't care less if the HTML has a bad attribute or two. On the other hand, if you are designing a website, it would be great if a standard browser presented a way to request that it tell you everything that it is ignoring or manipulating to create something sensible. That way you could find all those typos and nonsensical layout instructions that it is cleverly avoiding and stop wondering why it's ignoring your table's "witdh" attribute.
- I was trying to port a security provider MBean from WebLogic 8.1 to 9.2 and ran into a problem where my new jars were simply being ignored by WebLogic and so I was not able to configure them in the administration console. I assumed the problem was that I had screwed something up when I made the handful of necessary changes for the port. I cranked up every possible debug setting in an attempt to find any hint as to why it was balking, even an "invalid configuration" or something. Finally I just went back to first principles, and walked through my build script and the WebLogicMBeanMaker process to see if anything jumped out at me. I discovered that I had modified a path name incorrectly, and so the MBeanMaker was putting files in the wrong place. This really bothered me because it was actually silently ignoring problems twice: first when the MBeanMaker was run in that it wasn't telling me that it was essentially creating a bogus resulting jar file (I examined the contents of the jar files, which did have some content, but since the MBeanMaker works all kinds of internal magic it wasn't obvious that anything was missing), and then again when the runtime server was skipping the bad jar file. In either case they might have alerted me and saved a lot of blind debugging.
To some extent, I blame programming languages themselves for this phenomenon, which tend to only give you two standard options: report an error, or move on. For example, Exceptions are built into languages like Java at the core level, but Exceptions indicate that something serious enough has occurred that you want to stop what is happening and pop stack frames until you find someone able to handle it, so your only choice is report an error (throw an Exception) or not (move on). It would be nice if there were a third option, throw a Warning, let's say, that didn't change the stack state at all. You could choose to wrap a block of code with a warning handler and do something sensible, or ignore it and it would be passed up the stack until something did, but after the handler executed, you would return the stack to the state it was at the time of the Warning. In Java-esque code:
public void doSomething() {
try {
doSomethingSemiDangerous();
doTheNextThing();
}
warn(Warning w) {
reportWarning(w);
}
}
public void doSomethingSemiDangerous() {
startActivity();
if(variable == badState) {
throw new Warning();
}
continueActivity();
}
Please excuse the weird blockquote formatting; that is my lazy approach to indenting the method bodies for clarity. In the second method, continueActivity() would always be reached, because the stack state is preserved during the Warning handler chain, and the same would be true of doTheNextThing(), which would be reached whether or not the warn{} block were entered. This really isn't anything fancy in terms of a programming language. In Java, it could be implemented fairly easily with Aspects. The idea is simply to encourage developers to report not just problems that require aborting the current process, but also problems that don't require it, without needing to do something clunky like pass a callback around to report warnings, or adopt some writing to stdout convention, or tack on logging calls everywhere. Hopefully, if this notion were built into the fabric of the language, developers would do more of it.
I implore the development community to spend some time considering the users of your systems that need this information, and make a concerted effort to report non-fatal problems in some form. I think ideally, it would entail adding a well-known setting that can be enabled so that non-technical users don't get spooked by the messages, but those who need them can get at them. If you want write a language with built in support for "Warnings", so much the better.
