Sohan's Blog

Living the Developer's Life

Forget Me Not! Object Oriented Design in Custom Exception

When designing custom exceptions, you may forget about old school OO fundamentals. As a reminder, lets take a look into the following custom exception classes.


StorySaveError
StoryDescopeNotAllowedError
StoryCompleteError
StoryNotFoundError
StoryDeleteError
StoryDeleteNotAllowedError

These exceptions are really useful in my application. But the bad thing is, they all derive from StandardError class, whereas there should be a base class, may be StoryError, which is more meaningful and useful. So, we can have the following-


class StoryError < StandardError
end
StorySaveError < StoryError
StoryDescopeNotAllowedError < StoryError
StoryCompleteError < StoryError
StoryNotFoundError < StoryError
StoryDeleteError < StoryError
StoryDeleteNotAllowedError < StoryError

With the addition of a base class for all Story related exceptions, I can write cleaner/better code.

  • When I am not interested about the specific error, I can just use rescue StoryError to catch ‘em all
  • I can place a common error handling routine for all Story related exceptions
  • I can add new exception types without altering the codes where the specific type of StoryError is insignificant

From my experience, I found that most people are not cautious about OO when desiging custom exceptions. (because they are exceptions!). Nonetheless, if you follow the OO guides, it will pay off for sure.

Comments

Sohan
Yes, that is another way. Usually, people use ErrorCode to designate such cases. For example, WebException has many error codes in .Net. One code denotes timeout, another denotes network failure and so on.
One quick point, I saw you added attr_accessor :message. message is already an attribute of the Exception class, the base class of all Exceptions. So, you need not define a message property again. Its there and you can use it for free!
Samiron Paul
Just sharing a little experience. A situation where user may be failed to delete a task for any of two type of restrictions. But in both case "TaskDeleteNotAllowed" type exception will be raising. Hence it will not be possible to show the exact reason to user. Now instead of being so conservative by creating a new class, we came out in the following way

Added a attribute in TaskDeleteNotAllowed:
Class TaskDeleteNotAllowed < StandardError
attr_accessor :message
end

Create an instance of the class while before raising:
exception = TaskDeleteNotAllowed.new

Setting custom message based on the error occurred and raise that:
exception.message = "Task is completed" #or any other message
raise exception

Of course rescuing the error as following:

rescue TaskDeleteNotAllowed => error
#show {error.message} in flash or write in log

That makes a proper sense to user whenever she fails to delete a task.

Anyway, being concerned with OO fundamentals in designing custom exception handlers is realized again.

Thanks for the post