Grenade-based programming: Throw, but never catch 🧨
Why removing catch-statements in code can dramatically improve the quality of our software. The difference between expecting and preventing exceptions.
"We write perfect bug-free code" is a lie that no experienced developer can say with a straight face. We have even used the monicker "bugs are a feature" as a battle cry when we find a bug. So what can we do to improve quality? Let's introduce grenade-based programming!
What can you throw but never catch? Answer: A grenade!
Grenade-based programming is straightforward: Our code can have as many throw-statements as we want but only a few, preferably none, catch-statements. Writing a catch around the entire application is a no-go.
When a computer encounters a throw statement, I imagine a waiter throwing his hands up in the air and saying, "Well, I have no clue what I need to do next," followed by dropping whatever was being carried. The computer then looks for a catch statement, hoping to catch my meal before it hits the ground.
With that picture in mind, grenade-based programming is like having a restaurant where the kitchen and the dining area are connected by an obstacle course. Sounds fun in theory, but I would have low hopes that my food would arrive on time. So why do I claim this a good idea?
Over the years, I have seen a lot of code riddled with catch statements. Sometimes, the catch could never occur because an exception couldn't happen. In those cases, the best course of action is to remove the catch statement; after all, it's code that will never be triggered.
Complexity in code is mainly caused by branching (if/else, switch) and loops (for, do, while) in which the behavior of the application changes based on the state of the application. In fact, all branches and loops have, on a lower level, a jump statement in them.
- If true, then jump to x, otherwise jump to y
- If the loop counter is below 10, then increase the counter and jump to the start of the loop.
The more complexity our code has, the more likely it will have a logic bug. The more likely our code has a bug, the more likely our users will complain. And the more likely our users complain, the more likely the company doesn't create value. At the end of the day, our users expect code that works, no ifs or buts about it.
Remember the waiter at the start of our story? Imagine a restaurant where waiters constantly throw their hands up in the air and customers always catch their meals. No matter how skilled the customers are at catching their meals, I still would recommend something other than such a place. So why should we accept that same behavior in our code?
There are two ways to solve this:
- Reduce the number of throws
- Reduce the number of catches
Reducing the number of throws might seem logical until you realize that throws are done for a reason. A computer can't divide by zero because there is no answer. Thus, a developer can always have a valid reason to throw. Throwing an exception occurs because we encounter an exceptional situation and have no solution. The average of no numbers is unknown and not zero. And as the owner of a restaurant, you can't guarantee that your staff never trips.
One might argue that the same applies to catching errors, but when you write a catch statement, you are instructing the people who order food to be aware that they need to be mindful that food is constantly being dropped in this "fine establishment."
Catching an exception should be done only when there is a clear cause and recovery. You should avoid writing a catch statement if you didn't identify a clear cause and an explicit path to recovery.
Someone might complain "that this might result in the entire application charging," which is correct but not the big issue we think it is. Your application crashing to the desktop (CTD) is a clear signal that there is a quality problem in your solution. If you only catch it to log the error message, you hide an issue from the user. Even if you inform them about the problem, it sounds like: "Sorry we dropped your meal, could you please leave and come back again?". But ain't that the same as telling our users to restart the application? Or refresh the webpage? The only reason why our users accept it is because the cost is low.
By removing catch statements, the cost of an exception increases, which results in developers putting more effort into preventing it from happening in the first place. And that is the increase in quality that we want.