Exceptions, exceptions — wait, what?
Recently I’ve made a point, then thought a bit more about it and decided to write a small-talk article.
With C# imperative OO background, I am pretty used to exceptions, we have exceptions everywhere.
Think of Java. I barely remember one beer talk in Wroclaw when I said that Java is exception oriented language. And it’s alright, it’s still a good programming language, people wrote a bunch of code with it and continue on doing so.
Here’s the sample of my code, usually we have something like this.
What is wrong with that? Nothing is wrong if you have only OO experience.
If I had asked people what they wanted, they would have said faster horses.
Sometimes I think of this statement in software engineering context. A lot of people just don’t want to use some tool because it seems too complicated to them. Horses are easy to ride and easy to understand, everyone is riding a horse.
Everyone is doing that kind of thing in OOP. As you see, I didn’t wrap everything into try/catch block, but actually, I could, I even could try to handle all of these. As for me, I don’t consider exceptions as silver bullet practice, they are no good and no bad at the same time. Short answer: it depends. Depends on the domain (e.g. healthcare), time to refactor, team skills, language ecosystem and much more to go.
An exception is when a member fails to complete the task it is supposed to perform as indicated by its name.
(Jeffry Richter, CLR via C#)
Think of this thesis.
Every person with FP background would say that exceptions are crap and you shouldn’t produce side effects, shouldn’t change your control flow, keep it pure et cetera. And I mostly agree on that, purity, transparency is the new black.
I would say that sometimes you still need to raise an exception, but that should be really an exceptional situation like StackOverflow. Or imagine you are calling a web API server. Of course, you expect it to work every second of the time. An exception is when it’s down for some reason. An exception is when you have request time out.
The casual situation is when user types “daslkjdsalk#()Dk” into his age field. It’s expected that user is foolish.
The main point I want to mention here that you need to evaluate if your case is really exceptional before you raise an exception.
And if it is really exceptional (<1%), raise an exception, you are good to go. But there’s one more thing: make this code readable. E.g. in Java try/catch blocks are extremely big, even boilerplate and hard to break up. All other considerations like correctness and performance are second-class citizens. If it’s readable, the rest can be taken care of in maintenance, something could be refactored et cetera. But if you have not readable spaghetti code then you should better just throw it away and rewrite from scratch. I think that’s how modern software gets built: you try, you learn, you do, you repeat.
How can I don’t say about monads?!
In FP we have something called monad. I will just assume I don’t need to explain whole monad thing, let’s pretend you already know about it.
What they have to do with exceptions?
I think of Maybe monad as an instrument of almost purity.
Simply saying Maybe is Option type that can hold Something or None. Basically, Something is a value itself.
So in your function you just assign the value as Something if everything went well. Or return None if something went wrong or an error occurred. That makes you method very transparent and pure — it always returns something or nothing. Is it easy to test? Probably.
And the next function in your calling stack should handle both cases — Something and None. It’s much like returning null from a function except it’s done in a type-safe way which forces you to deal with None case. So you just can’t have something like NullReferenceException. Notice that Maybe monad is KISSing, there is no additional information about why you don’t have value in, simply it just says that you don’t have it. It’s not like we are used to doing with FileNotFound, TimeOutException, NumberFormatException, UriFormatException etc etc etc. There is no additional information about the problem, just 1 or 0.
The best case of using Maybe I would say is getting a value from a dictionary by a key — it’s Something or None, there is nothing exceptional about it. There shouldn’t be ValueNotFoundException.
I can’t say that raising an exception is bad and the same way I can’t say it’s good.
It just depends.
But I’m sure that there are situations where I should raise an exception and where I can deal with just Maybe/error-code/bottom-value/whatever.
There are a lot of different approaches and I think that’s software engineering is all about — it’s about choices, it’s about thinking of different cases, it’s about getting your mind blown.