3

I am talking based on experience with Java and C#. I do not know if other language have different exception handling implementation.

In order to achieve loose coupling, we need our code being programmed to use abstraction rather than implementation. However the exception handling case is the opposite. The best practice is you need to handle specific exception type (SqlException, StackOverflowException, etc).

This thing may be better (or not) in java thanks for it's Checked Exception, there is a kind of "contract" between the interface and the consumer. But in C# or for the Unchecked Exception there is no contract about what exception can be thrown by the interface.

For example, say that we use Repository Pattern to decouple the DAL with BLL. The simple catch exception usually be used like:

public void Consume()
{
    try{
        productRepository.Get(k=>k.Id == "0001");
    }
    catch(Exception e){
        // handle
    }
}

In more specific case we usually use SqlException. However it means that we must know that the ProductRepository is a repository to database server. What if the implementation changed to use file repository instead? Now you need to catch FileNotFoundException or something like that.

Why does it violates the "code to abstraction" principle? And what can we do to prevent it?

marked as duplicate by gnat, Euphoric, GlenH7, Kilian Foth, user40980 Jan 17 '14 at 17:31

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • @gnat while similiar, I believe both question are different. I cannot argue though that your references can also explain my question as well. For Euphoric: No, I am not asking for inheritance here, just the pure exception handling. – Fendy Jan 16 '14 at 7:31
  • 2
    You cannot have abstractions without either inheritance or realization of interfaces. LSP applies to both. – Euphoric Jan 16 '14 at 7:32
  • @Euphoric Ok I get it now. But still my question is not related to LSP because I refer to the interface itself rather than base class in your referenced question. If you still want to make it related, I can say that "every interface implementation violates LSP when throwing exception", because it strenghthen the precondition. Taking assumption that interface itself will not throwing any exception other than NullReferenceException. – Fendy Jan 16 '14 at 7:44
7

You should handle a specific case where it's appropriate to handle that specific case.

In your example, the consumer is not the appropriate abstraction level to handle a SqlException, as you've surmised.

The repository itself, which knows it is retrieving from a database, should be what handles the SqlException, perhaps repackaging it into a more application-specific and custom DataAccessException that can then be handled appropriately by the consumer.

If you change the repository implementation to pull data from, say, a web service, that repository can handle an HttpException and repackage it into the DataAccessException. Or an XML repository can handle XML-specific exceptions and repackage them. And so forth.

  • This is the most reasonable answer I can accept. I still wonder with the "lack" of contract for the exception between the interface and consumer. However if you say that it is an exception after all, maybe it is acceptable. – Fendy Jan 16 '14 at 7:33
  • If you consider (or build) your application to have different layers with different responsibilities, then there's an interface between each layer, as well as an interface e.g. to the database or another system. Each layer has to opportunity to abstract away any implementation details, such as with the data provider example in the answer. – Rory Hunter Jan 16 '14 at 10:56
1

It depends heavily what kind of exception you are talking about. Exceptions are meant to be exceptional, but some aren't.

For example, lets say interface method IProductRepo.Get has implied condition, that it always returns a product. But for some reason, the ProductRepo implementation of it can throw an exception if the product doesn't exist. In this case you can handle the exception in Consume and act appropriately in a case when product is not found. But like you assume, this is violation of abstraction, more correctly a violation of LSP as discussed here. This usually implies your abstraction is wrong and you should remodel it to correctly capture the additional case. In this example, you could say the Get method might return null if product is not found. This kind of exception can also happen if you have some assertions in your code and they fail. But this usually means bug in your code somewhere.

On the other side, there are truly exceptional exceptions or exceptions your application cannot predict. For example, loosing a connection to the DB is exceptional. The thing with those kind of exceptions is that they cannot be handled properly within the logic of the application. For example, if you did handle it like in your example, you would equate the case of not finding a product and loosing a connection and saying it is a same case. Which is obviously wrong. Those kind of exceptions can only be handled in generic way on program's boundary. In case of UI application, all you can possibly do is to display "The operation cannot be finished because: (reason here). Try again later." and hope the user doesn't fill it as a bug report. There is no violation here, because it doesn't extend possible cases the caller has to handle. So it doesn't extend the contract.

-1

But exceptions are part of the contract!

You need to define which exceptions are to be handled in the interface.

Just as rental lease might specify "you must insure against fire damage" then an interface can specify that you have to handle SqlException.

In java at least the compiler gives an error if an implementation throws an exception not explicitly mentioned in the interface.

That is not to say that exceptions should be blindly passed through to the parent. As far as possible exceptions should be handled inside any implementation but sometimes this is just not possible. An implementation cannot hide the fact that it cannot connect to its data source be it a database, web service or whatever.

  • how does this answer the question asked? – gnat Jan 16 '14 at 8:31

Not the answer you're looking for? Browse other questions tagged or ask your own question.