Why you shouldn’t throw Exceptions in your Code
Bending the Clean Architecture principles
Introduction
Exceptions are common in most of the languages. You even have the famous memes with the NullReferenceException, or the jokes about memory management and NullPointerException. You can even create your custom exceptions which is awesome right? But with great power, comes great responsibility…
The Problem
Let’s say your building an API, or any application really. The problem is not within the exception itself, each application have some sort of business layer or logic. Most of the codebase I saw used Exceptions to validate the logic, if you see something wrong, break your code.
Or when you want to break out of a function, without actually returning a result thus breaking your execution. I saw this as a common excuse to use and trigger exceptions.
Now, we expect our functions to exit and throw some exceptions. If you use Java, you are obligated to catch or rethrow and handle those. In C#, you don’t have to so let’s be language agnostic for a bit.
Don’t you think it really affect code readability ? Didn’t you find yourself explaining a chunky function with its multiple throws… Or didn’t you find it a bit strange to see your constructor polluted with validation and throws? Or debugging and tracing exceptions messages and stack in your code? Because they are everywhere...
I didn’t talk about performance yet, in this cloud native world where you want to squeeze every bit of performance of your API. A 3% optimization would cost you less instances in Kubernetes, therefore less money spent and more profit. Let me tell you that after refactoring some of my old projects, I saw a steady 10% without blinking !
Your Smart Problem Solving Skills
Well, disregarding the performance benefits, you think: Let’s centralise the Exception handling of all your application. You want to regardless of the exception, catch the exception and display the appropriate error code and message. That’s solve the problem and sounds familiar right?
The famous Exception Handling middleware. You just put it in the API’s pipeline and tada ! you can throw as many exceptions as you want and someone will want to care of them for you.
Reflecting
An Exception for me is something that cannot be handled or expected, so you’re obligated to halt all the code flow and throw something. If you know that an entity might not pass the validation tests, you should not throw an exception. This is considered also a “normal” flow. Users are expected to input something wrong at some point. You just want to indicate that where and what is the error that is preventing the action… so, why the throws?
Downfalls and Alternatives
Just explain for newcomers how this magic middleware works every time, lose the performance benefits you might gain just for removing throws in your code. Break the SOLID principles in each and every constructor, be inconsistent and implement all your business validation in Exceptions.
Didn’t you find yourself searching and adding inside constructors that are using across all your codebase? This sounds scary as hell right?
Or when you mark your code with debuggers to follow a single code flow, in your mind, an exception can be triggered and can exit from anywhere so that’s how you should follow the execution.
Don’t forget that business rules and validations are expected to grow and change as your domain and business matures, do you find this implementation scalable?
For me there’s actually no benefit from using Exceptions in those cases. You’re losing so much by just throwing code on scenarios that are considered and should be expected for you to handle. It’s great to have some exposure on other languages and how things are done. I am a huge fan of functional programming and how you can enforce the error and validation handling in return types. You can read about Discriminated Unions if you want to know more.
Exceptions use cases are rare nowadays, you might one to use them when you’re working on a library and you want to break when something that is fundamentally not correct, unhandled and unexpected is encountered. Other than that, there’s a handful of alternatives you might want to consider beforehand…