Besides understanding the most important structures of a system, it is an architect’s responsibility to understand and influence the design principles.
One common and important set of principles are those of error handling. It is good to have the same principles throughout the system as it produces fewer surprises and mistakes.
In this post, I will discuss you some principles that including checked exceptions and Null Object, which you may not fancy. But it is always good to think this subject through, so please come along.
My first principle is: "Deal with the errors directly".
What? Errors happen. Not my fault. Somebody else will have to fix this.
My point is that you should try to design your interfaces so that the implementation has a slighter risk of failing. E.g. a function called "getSingleResult" is asking for trouble. Either you get more than one result or you get none. In either case, you have to do something.
It is better to return a set of objects and let the client determine if the result was good or bad.
If you are asked to read object x from file y, you could return a Null Object if there is no x object in file y or if file y does not exist. Should the client think it is important whether there is a file y, it could find out by other means. You can not protect the client from the fact that a file is missing. It is annoying if all clients need to catch a FileNotFoundException when most of them would be happy with a Null Object.
The second is: "Tell your supervisor".
When you were a newborn you probably screamed when you were hungry. Later
you got old enough to ask for food.
The same goes for exceptions, you are just screaming that something is wrong and that someone else should fix it.
Instead, you should call your supervisor. There are times when you will be asked to deal with data that is inconsistent or use resources that you can not locate. Go call support. Writing in the log is ok if you have a tight check on your log scanning. Maybe there are such people out there. Otherwise the system should have a mechanism for calling support, so to speak.
Other than calling support, you should be silent. At least try to shut up.
The third is: “Use Null Object Instead of null”.
A bit Java specific, but it applies to other languages as well.
As soon as somebody returns a null, be it an innocent getter function, someone else will either have to check that or get killed by a NullPointerException. I hate those.
You may think that returning null is a perfectly sensible way of telling that nothing is there. Now we have exceptions to tell that us something is not ok, so we do not need return values that indicate errors. The benefit is that we do not have to get our code messy with checks after each function call.
int error = dothis(withobj, toobj)
if (error != ERROR_OK) return error
error = dothat(someobj)
if (error != ERROR_OK) return error
Get it? Why would I need to do the same with null when calling your code?
Use a Null Object instead. Let me decide if I need to know that there was nothing there.
If you design with “tell” rather than “ask”, it is easier to avoid both null and Null Object. Imagine having no return values, all methods have the void return type.
The fourth is: “Use Checked Exceptions”. (Java specific)
Now, remember that you should follow the other principles, but if you are going to throw an exception, why not tell your client beforehand? I mean, if you throw an unchecked exception, your client is caught off guard and will go down.
The objection is that the client code gets messy as it is forced to catch exceptions which it has no idea what to do with. Now, if that is the case, there is something wrong. It should be evident to the client what it should do.
Take login as an example. If you have a function “loginUser(user, passwd)”, it could fail for both technical reasons or wrong credentials. Either way, an exception will be thrown.
Now, since it is a login function, it is evident that the client would like to tell the user why it failed by showing an error message and remain on the same page. It is not messy, it is natural and better that returning null or throwing an unchecked exception.
If you design the function as "isCorrectCredentials(user, passwd)" you are asking for trouble as the login may fail for technical reasons as well as incorrect credentials.
As you may have noted, you should know your clients. Try to walk a mile in their shoes, i.e. try to use your own interfaces with a critical view. Look at actual client code.
Remember, these are only suggested principles. Make sure you have some where you work today!
One response on “Design Principles for Error Handling”