But in that case you probably still want to know about these failures, so you can review them from time to time, or see if there are upticks in failure frequency.
If you know that an operation is unreliable, you need to add retry / recovery logic and perhaps log or increment a metric that you can track what's going on; a high number of failures often indicates an exceptional situation.
In some cases, your retry logic will be a "Please try again" message to the user. I think that's perfectly acceptable, but you'll still want to know about it.
I have a third party which returns errors ~20% of the time outside of working hours (yes, really).
1. Exceptions should be sent to sentry. 2. Exceptions should not be normal. 3. Do not log.
Solve for ability to review & debug after the fact.
Then presumably those errors shouldn't be exceptions. Of course, there's a lot of a lot of assumptions behind this:
1. You have control over the code that interfaces with the third party. Otherwise presumably you'd have to write a shim that catches the exception and turns it into an error value, and that's probably not worth the effort.
2. You're work in a language that doesn't type check exceptions (i.e. not Java with checked exceptions) and your language also doesn't have a nicer way of handling errors as a (discriminated) union.
3. Your co-workers will go complete bananas if you start using some sort of result type or [success, value|error] tuple instead of an exception because that's how they've done it for 20 years.
The reason for this is that exceptions in most languages escape the type system and are in general more awkward to catch.
Of course, I'd also disagree with "do not log" in this context, though I might prefer a logging mechanism that allowed me to write queries on it (like recording values in a database).
Even if you really really like error return codes and really really don't like exceptions, you'll likely agree that writing very un-idiomatic code that goes against the grain of the language and all the libraries you might be using is likely a much bigger loss than the value you might have added by avoiding exceptions in your part of the block.
Out of curiosity, in what languages are error return types non-idiomatic?
This isn't to say the idioms are never broken or that they shouldn't be broken. I agree that if you are doing something like parsing a string to an integer, that should probably be a result type and not just throw an exception.
In languages like Java an Python, you can return error values but because you can also always return nulls, you're just making more trouble for yourself than it's worth avoiding exceptions.
It is not easy to stay away from exceptions if your language supports them.
But even for exceptional exceptions, you may still want or need to retry or branch based on what was thrown.
It's not an either-or situation though. Even if you let the exception bubble up and sentry logs the exception, logging performed prior to the exception and at the time the exception is caught (prior to being bubbled up) as valuable context to how the exception happens, which can lower debugging time.
The exception just tells you that something went done, it doesn't always have the reason why something went wrong. And the context for why is not always available at the time of raising the exception (the context may be from a prior function call, or the consumer of the function that raised the exception).
Usually, but not always. That is, for the classic "exceptions should only be used in exceptional cases" scenario, this is usually what you want to do.
A good portion of the time, though, this scenario doesn't apply. You're dealing with a subsystem that is throwing an exception (for good reasons or bad) but no, you don't want to just the application crash. You want to ... catch it, and do something else.
Which is what try-catch was devised for in the first place, after all.
Ok, I did all that. And I still want to know why this bug report happened, and logs help me. Why should I Not Log?
Yes, but you should catch as soon as possible (or validate stuff as soon ass possible) and re-throw with a better error message if possible. You will thank yourself when some problem appears and instead of a random "errorcode 123" you get a detailed message like "Operation Xyz failed with errorcode 123";
And then catch it at the highest level, including all the stack trace. And then maybe send it to sentry, or log it, put it on data dog.
But don't catch exceptions all over your application code.
I have a related mental model for this: When you crash, crash loudly.