Question

I've run into a debate between a few friends and I. They prefer general exceptions such as ClientErrorException and ServerErrorException with detail as fields of the exception, whereas I prefer making things more specific. For example, I might have a handful of exceptions like:

  • BadRequestException
  • AuthenticationFailureException
  • ProductNotFoundException

Each of these built based on the error code returned from the API.

Following Advantages of Exceptions this seems idiomatic to Java. However, my friends' opinion is not exactly uncommon.

Is there a preferred way in terms of code readability and API usability, or does it really just come down to preference?

Was it helpful?

Solution

The main difference between having many different exception classes, and having only a few, with more detailed information in the error text (for example), is that many different exception classes allow the calling code to react differently to different kinds of errors, whilst having only a few classes makes it easier to handle all kind of exceptions in a uniform way.

This is typically a tradeoff. It can be mitigated to some degree by using inheritance (a general base exception class for those callers who want to catch & log everything generically, and derived exceptions from those base class for those callers who need different reactions), but even that can produce a lot of unnecessary complexity if you don't be careful and stick to the YAGNI principle. So the guiding question should be here:

  • Do you really expect the caller of your code to react differently, with different flow of control, to those different kind of errors?

There is no one-size-fits-all solution to this, no braindead "best practice" you can apply each and everywhere. The answer to this question is heavily dependent on what kind of software or component you are designing:

  • some application, where you or the team has the whole code base under your control?

  • or some reusable component for third parties, where you don't know all the potential callers?

  • a long running server application, where different kind of errors should not break the whole system immediately and may require different kinds of error mitigation?

  • a short-living application process where it is enough in case of an error to display an error message to the user and then restart the process?

So the more you know about the potential callers of your component, the better you can decide about the correct level of detail for your exeptions.

OTHER TIPS

The answer depends on what level of error reporting we are talking about.

In general I agree with your friends, you should not make them more granular than needed to convey the cause of the problem.

If there is a common, well known exception for referencing null (NullReferenceException), you should not create your own MyObjectIsNullException. That would just add a layer of confusion for the human interpreter, an additional thing to learn that does not clarify anything.

Only when your exception is that special that there is no predefined one that covers the root cause should you create your own.

However, you do not have to stop there. The common error may occur in one of your components and you may want to convey there was a problem in your component. So not just what went wrong but also where. Then it would be appropriate to wrap the first exception in a MyComponentException. That will give you best of both worlds.

First it will be clear your component ran into trouble. On a lower lever, the specific cause would be in the inner exception.

Licensed under: CC-BY-SA with attribution
scroll top