Nested Code
Hey there! Today, let’s focus on one topic that can significantly impact readability: nested code.
Nesting occurs when we place one or more blocks inside another, often seen with loops or conditions:
for (...) {
if (...) {
if (...) {
for (...) {
// ...
}
}
}
}
While nesting is common, too many levels can make code harder to read and maintain. Let’s explore this concept with an example in Go. Imagine we are working on a new project, and we need to understand the following function:
func join(s1, s2 string, max int) (string, error) {
if s1 == "" {
return "", errors.New("s1 is empty")
} else {
if s2 == "" {
return "", errors.New("s2 is empty")
} else {
concat, err := concatenate(s1, s2)
if err != nil {
return "", err
} else {
if len(concat) > max {
return concat[:max], nil
} else {
return concat, nil
}
}
}
}
}
This join
function concatenates two strings and returns a substring if the length is greater than max
. Meanwhile, it handles checks on s1
and s2
and whether the call to concatenate
returns an error.
From an implementation perspective, the function is correct. Yet, the heavy nesting makes it hard to follow the logic and requires a significant cognitive load.
Now, let’s look at a refactored version:
func join(s1, s2 string, max int) (string, error) {
if s1 == "" {
return "", errors.New("s1 is empty")
}
if s2 == "" {
return "", errors.New("s2 is empty")
}
concat, err := concatenate(s1, s2)
if err != nil {
return "", err
}
if len(concat) > max {
return concat[:max], nil
}
return concat, nil
}
You probably noticed that understanding the second version requires less cognitive load despite doing the exact same job as before.
As Mat Ryer wisely advises:
Align the happy path to the left; you should quickly be able to scan down one column to see the expected execution flow.
In the first version, the expected execution flow was difficult to distinguish due to the nested if/else
statements. Conversely, the second version allows us to scan down one column to see the main execution flow and down the second column to see how edge cases are handled:
In general, the more nested levels a function has, the more complex it becomes to read and understand. Let’s keep this rule in mind to optimize our code for readability.
Explore Further
Do you have another important rule in mind that significantly improves readability? Let’s discuss it.