Single vs Multiple Try-catch - Exception Handling #1
While practicing any programming language, every developer encounters the topic “Exception Handling“.
Let it be Java, Ruby, Python, etc., every language has exception handling as one of its topics.
Whenever we hear Exception handling, the first word which comes to mind is “try-catch block“. In Programming tutorials and during practice, we write a single try-catch, the focus being to understand how to catch the errors.
But Try catch blocks are not only for catching and printing the exception, It has other functionalities as well like
Performing rollback of functions which executed before the failure functions
Perform verification checks of the existing system in case of failure of code in the try block
Retry of failure code(Not a best practice😕)
Along with this, the main question with the developer when they start working in any organization is “Should I write a single try-catch block or Multiple try-catch block“
Single vs Multiple Try-catch Blocks
TLDR:
Write a single try-catch block when
Your goal is to only catch the exception.
Implement multiple try-catch blocks when
Your goal is to perform a rollback operation or perform verification or retry code. i.e any of the above 3 points
Detailed Answer:
I have been discussing this topic while doing PR reviews of developers on how exception handling can be improved. One misconception among developers is If your code is huge, multiple try-catch is required.
Selecting single or multiple try-catch should be based on the use case of what operation you would perform inside the catch block and not the size of the codebase.
Let’s say you have to add exception handling into the access management system in your organization,
Demo code:
Code in this article is in python but it is applicable on all programming languages
All code examples is more like a pseudocode, organisations use frameworks like django or spring for build systems
# import statements
# Section 1 - Defining Functions
def check_user_access(user, access):
# code logic
return user_has_access
def grant_access(user, access):
# grant code logic
return grant_pass_or_fail
def revoke_access(user, access):
# revoke code logic
return revoke_pass_or_fail
def last_access(user):
# code logic
return user_access
def revoke_all_access(user):
# code logic
return access_revoked_or_fail
user = 'rahul.jaisinghani' # hardcoded just as example
access = 'github_admin' # hardcoded just as example
Section 2 - Trigger logic
def trigger_access_management(argument):
switcher = {
0: check_user_access,
1: grant_access,
2: revoke_access,
3: revoke_all_access,
4: last_access,
}
func = switcher.get(argument, lambda: "nothing")
return func(user,access)
Section 3 - Flow logic
if __name__ == "__main__":
# calls check_user_access function
argument=0
trigger_access_management(argument)
# calls revoke_all_access function
argument=3
trigger_access_management(argument)
The first question which should come to your mind is
What is my goal for adding exception handling or try-catch block?
Single Try-catch
If our goal is to just catch exceptions then exception handling will be added in Section 3 i.e In part of the code where execution starts and ends. Here we will just add a single try-catch
.....
Section 3 - Flow logic
if __name__ == "__main__":
try:
# calls check_user_access function
argument=0
trigger_access_management(argument)
# calls revoke_all_access function
argument=3
trigger_access_management(argument)
except Exception as e: # In python, except is used instead of catch
# print the error or send it to alerting system
Multiple Try-catch
if our goal is one of
Performing rollback of functions which executed before the failure functions
Perform verification checks of the existing system in case of failure of code in the try block
Retry of failure code(Not a best practice😕)
I will use Multiple try-catch blocks. This block will be added in Section 1 and one inside each function
Since every catch block will have a different code for implementing the above cases, there will be multiple try-catch instead of one
.....
# Section 1 - Defining Functions
.....
def grant_access(user, access):
try:
# grant code logic
except Exception as e: # In case of any error in grant code, we might trigger failure mail or use any alternate way or revert all operations
# revert grant logic
return grant_pass_or_fail
def revoke_access(user, access):
try:
# revoke code logic
except Exception as e: # In case of any error in revoke code, we might trigger failure mail or use any alternate way or revert all operations
# revert revoke logic
return revoke_pass_or_fail
.....
Rollback code in the except block inside both of the above functions will be different as both have different use cases.
FAQ:
What If I want to catch exceptions and perform rollback operations? Which method should I use?
Use Multiple try-catch blocks in that case(section 1 in above example). Add your exception catch logic like print statement or sending error to alert system inside each try-catch block
What happens if I add try-catch in both Section 1 and Section 3 in the above example
Your decision on where to add the exception handling will be based on which code you want to cover and what operation you need to perform.
Example: Adding it in both sections just for catching exception does not make sense. You can only add it in section 3 as it the start and end exection point of your code