Code style is a topic that has ignited many arguments and while it is not an unimportant topic there is arguably a far more important topic that often gets overlooked: code structure.
One “error” that I’ve seen a lot of developers make concerns how they structure their conditions.
In some cases a condition has two equally valid alternatives:
if user_is_logged_in:
render_account_page()
else:
render_login_page()
However in other cases, one of the branches is the happy path, while the other is the non-happy or error path:
if some_operation():
# happy path
else
# error path
In the simple case as shown above, this form of the condition might be fine. However once the code becomes more complicated, you get what I like to call “staircase code”:
if operation1():
if operation2():
if operation3():
if operation4():
if operation5():
# handle success
else
# handle error
else
# handle error
else
# handle error
else
# handle error
So what’s wrong with staircase code? Well, it makes it difficult for the person reading the code to determine which error handling statements are associated with a particular condition statement.
In some cases the reader might not even notice that error handling code is missing entirely, which could lead to a bug. Did you notice that the above example is missing some error handling?
So what is the alternative? Let’s look at the base case again:
if some_operation():
# happy path
else
# error path
If we invert the condition, we get:
if !some_operation():
# error path
else
# happy path
Which is logically equivalent to:
if !some_operation():
# error path
return
# happy path
If we apply this principle to the staircase code from above, we get:
if !operation1():
# handle error
return
if !operation2():
# handle error
return
if !operation3():
# this is the error path that is missing in the above example
return
if !operation4():
# handle error
return
if !operation5():
# handle error
return
# handle success
One of the reasons I like golang so much, is that handling errors like this is idiomatic:
value, err := Operation()
if err != nil {
return err
}
// do something with 'value'
Remember, if your code is used by enough people, 1-in-a-million events will occur on a regular basis.
Check for errors and handle them!