Live data from Hacker News

Code Design Decision – Always throw custom exceptions

github.com

61–70 of 92 posts

Re: Code Design Decision – Always throw custom exceptions

#61

Earlier quoted context omitted.

The whole DomainError thing only makes sense if you expect someone to handle this error (and by handle, I mean doing something other than logging and aborting some operation), or if you are writing a very generic library. Otherwise, it is wasted time and extra complexity that makes the code harder to read.

Yes, that's true, just as it is with exceptions in the original article. However, if you are writing the code and it's callers, if you don't want to handle the error, why even have it? Just log the results there and move on.

> However, if you are writing the code and it's callers, if you don't want to handle the error, why even have it? Just log the results there and move on.

Well at very least you need the caller to know that the operation didn't succeed. And if the failure is deep in the call stack, you may not have enough information to log a meaningful error. Returning errors and wrapping them with a description as you pass them up the stack means you can have a single meaningful log message at the "top level" (wherever the buck stops).

Re: Code Design Decision – Always throw custom exceptions

#62
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

I can't agree with any of these points.

1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk).

Not sure how this relates to the code design decision

2. Consumers of your code will not know how to deal with those exceptions.

Not sure the point here but if the argument is that the caller won't know how to deal with the third party exception, I disagree. Typically it just needs to return a single exception type that wraps any underlying cause. Caller can just either decide to deal with it or rethrow.

3. Most of exceptions are unrecoverable (that's why they are called exceptions), the best course of action is to crash, which happens by default.

If the database is unresponsive do you want to crash your program? I wouldn't. I'll usually retry until its available.

4. You debug those exceptions by looking at stack trace. Adding extra levels just to give a fancy meaningless name to an exception does not help.

Really don't think an extra trace in the stack is a reason to not create a well defined contract.

5. The whole point of exceptions is to propagate. Parthenon essentially suggests converting exceptions into return values.

I didn't see anywhere in the doc where they mentioned converting exception into return values. Wrapped exceptions are still exceptions.

Re: Code Design Decision – Always throw custom exceptions

#63
post #38

Earlier quoted context omitted.

This is the problem of Java's implementation of checked exceptions... because they are not generic. Which forces middle layers to make impossible decisions like this. If the type system were more capable, they'd just be equivalent to typed generic error returns, which work fine.

I mean, can't you just catch Throwable (base class) and be done with it?

This forces client code to handle arbitrary exceptions and it loses the information about which specific exceptions are actually thrown. This is like having Object as the return type on all functions, and having callers do instanceof to see what type of result they got. Exceptions should be part of the semantic contract of functions/methods just like return types are.

Re: Code Design Decision – Always throw custom exceptions

#64
There are some nice arguments for not overengineering in the comments here, as well as some for there still being merit in explicitly saying what could (typically) go wrong in the execution of a program. We've already seem the extreme of "never create your custom exceptions", or even something to the tune of "exception handling is a maintenance burden", but I can't help but to wonder about going in the exact opposite direction - even further than the article suggests.

What if we had a language that only had checked exceptions and forced you to deal with anything that can go wrong. Launching a program? You better have some code to deal with an out of memory exception, or some code for dealing with a stack overflow exception. Working with some maths? Well, you better define what should happen in the case of number underflows or overflows, as well as division by zero or whatever else can be inferred by what operators you use. Dealing with a network? Well, be prepared to handle dozens of types of network failures, the brittleness of networks being laid bare to you. Want to deal with reflection? Well, there would probably be none, to avoid too much dynamic behavior.

It's rather obvious why we don't really have languages like that, but at the same time - if writing code in a language like that would be "possible", then surely there's a domain or two out there that might benefit not just from enforced 100% test coverage, but also every single possible error being handled, or at least laid bare. If a program should crash upon particular errors, then the developer might say so explicitly, or otherwise provide logic to recover from those, without ever missing any place where things could go wrong.

Contrast this made up language with your typical Java project: you might use the Spring framework and have a method that exposes a RESTful API that returns some JSON to the client. You'd be amazed at just how many different issues you can run into with even the simplest implementations, it's like a never ending path of discovering more ways for your programs to go wrong. If you can sometimes benefit from your IDE going "hey, this code might throw a NullPointerException", then how much additional assistance you'd benefit from (and how much error handling should be encouraged/enforced) is probably up for debate!

Re: Code Design Decision – Always throw custom exceptions

#65
post #61

Earlier quoted context omitted.

Yes, that's true, just as it is with exceptions in the original article. However, if you are writing the code and it's callers, if you don't want to handle the error, why even have it? Just log the results there and move on.

> However, if you are writing the code and it's callers, if you don't want to handle the error, why even have it? Just log the results there and move on. Well at very least you need the caller to know that the operation didn't succeed. And if the failure is deep in the call stack, you may not have enough information to log a meaningful error. Returning errors and wrapping them with a description as you pass them up t…

[deleted]

Re: Code Design Decision – Always throw custom exceptions

#66
post #63

Earlier quoted context omitted.

I mean, can't you just catch Throwable (base class) and be done with it?

This forces client code to handle arbitrary exceptions and it loses the information about which specific exceptions are actually thrown. This is like having Object as the return type on all functions, and having callers do instanceof to see what type of result they got. Exceptions should be part of the semantic contract of functions/methods just like return types are.

Exceptions are a return type of functions. They return via a different path but there is no possible way you could disagree that they are a form of return.

Re: Code Design Decision – Always throw custom exceptions

#67
post #66
post #63

Earlier quoted context omitted.

This forces client code to handle arbitrary exceptions and it loses the information about which specific exceptions are actually thrown. This is like having Object as the return type on all functions, and having callers do instanceof to see what type of result they got. Exceptions should be part of the semantic contract of functions/methods just like return types are.

Exceptions are a return type of functions. They return via a different path but there is no possible way you could disagree that they are a form of return.

Exactly my point?

Re: Code Design Decision – Always throw custom exceptions

#68
post #13
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

I think there are two kinds of exceptions in languages that have them as their error handling mechanism. 1. Exceptions you expect your consumers to handle. 2. Exceptions you don't expect your consumers to handle. The first one I would argue you should wrap third party exceptions. There is in nearly every case important context in your code that the thrower of the third party exception will not know and whoever is rea…

The problem is that it should be the caller that decides which category the error falls within, but most languages forces the callee to choose.

Re: Code Design Decision – Always throw custom exceptions

#69
post #59
post #48

Earlier quoted context omitted.

Haha, that's actually a good point. A single problem can affect dozens of modules, each having a different wrapper. If my db goes down, I very much prefer to see a single DatabaseConnectionFailed than a multitude of FailedToSaveObject, DatabaseError, CannotLoadData, IOError, SomethingIsWrongThisShouldNeverHappen, DBHostUnavailable all over the place. Good luck navigating through the noise and isolating those.

The article talks about solving that exact issue by wrapping all of those different exceptions so that you don't have to deal with them. Much easier to catch a single ThirdPartyInternalFailure exception than catch all the internal exceptions that could have caused an internal failure.

When library 1 through 10 take this approach to wrapping a common exception you get the above behavior. Obviously a single library should have a coherent internal story

Re: Code Design Decision – Always throw custom exceptions

#70
post #13
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

I think there are two kinds of exceptions in languages that have them as their error handling mechanism. 1. Exceptions you expect your consumers to handle. 2. Exceptions you don't expect your consumers to handle. The first one I would argue you should wrap third party exceptions. There is in nearly every case important context in your code that the thrower of the third party exception will not know and whoever is rea…

[dead]
Post reply on HN