DEV Community

loading...
Cover image for Clean up your code by removing unneeded indentation 完

Clean up your code by removing unneeded indentation 完

zachsnoek profile image Zach Snoek 2 min read

Indenting code, while usually not useful to a compiler, greatly helps us humans read code more easily. However, adding more indentation than what is necessarydue to extraneous if statements, for examplemight make a piece of code harder to read. Here is a brief overview of one technique you can use to avoid over-indenting code.

Take a look at the following simplistic example of a function getUserImages, which fetches a user's images from an API and then maps the data in some way:

const getUserImages = async (userId) => {
    if (userId) {
        const getImagesResponse = await apiClient.getImages(userId);

        if (getImagesResponse.ok) {
            const images = getImagesResponse.value;

            if (images) {
                const mappedImages = mapImages(images);
                return mappedImages;
            }
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

Yikes, that's a lot of indentation . You can imagine how complex code written like this might be hard to follow: With more indents, it becomes harder to track the block of code that a certain line belongs to.

The good news is that we can avoid a lot of this indentation! In this case, it's pretty simple because there are no corresponding else blocks; we can simply check for the inverse of the if statements and return early if the conditions aren't met.

Here's a refactored version of getUserImages using this technique:

const getUserImages = async (userId) => {
    if (!userId) {
        console.log("No userId provided");
        return;
    }

    const getImagesResponse = await apiClient.getImages(userId);

    if (!getImagesResponse.ok) {
        console.error("Error getting images!");
        return;
    }

    const images = getImagesResponse.value;

    if (!images) {
        console.log("User has no images");
        return;
    }

    const mappedImages = mapImages(images);
    return mappedImages;
};
Enter fullscreen mode Exit fullscreen mode

We've "flattened" the code out a bit and made it easier to read. Note that early guards like !images aren't very useful if there isn't a lot of code underneath it, but, again, this is a simplistic example.

This technique can also apply to other places where we might have multiple nested blocks of code, like in a for loop:

const processList = (list) => {
    for (let i = 0; i < list.length; i++) {
        if (i % 2 === 0) {
            if (list[i]) {
                // ... Do something
                // ... Do more things
                // ... Do even more things
            }
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

I find that immediately nesting if statements like this is usually difficult to read. The code in the inner if statement is indented four times; removing even one level of indentation can help us out:

const processList = (list) => {
    for (let i = 0; i < list.length; i++) {
        if (i % 2 !== 0) {
            continue;
        }

        if (list[i]) {
            // ... Do something
            // ... Do more things
            // ... Do even more things
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

This technique can't always be used to refactor hard-to-read indented lines of code. But, when possible, removing unnecessary indentation in your code like this will go a long way in making it more readable and maintainable for yourself and future developers.

Discussion (4)

pic
Editor guide
Collapse
jonrandy profile image
Jon Randy • Edited

These are quite poor examples TBH. The refactoring of the first one has added error logging, which confuses matters as the new code actually does something different to the original.

In both refactoring cases (particularly in the 2nd, but also in the 1st if the logging were not added) it probably would have been easier (and possibly more efficient) to simply combine the if statements

Collapse
ferenczy profile image
David Ferenczy Rogo鱉an • Edited

What you're describing is a valid point, it's a form of the source code optimization, but you're naming it wrong. The indentation is quite insignificant property of a source code, it's there just for better readability by humans and it's more (e.g. in case of Python) or less just a consequence of the cyclomatic complexity. And the cyclomatic complexity is, in fact, what you're trying to optimize, more specifically it's called optimization by reduction of the cyclomatic complexity.

When you reduce the cyclomatic complexity, the indentation is also reduced as the result or the consequence of such optimization. And such reduction has an impact on several properties of the source code (e.g. testing, clarity, code organization, performance, etc.).

On the other side, when you reduce the indentation, it doesn't have any impact on the cyclomatic complexity, you're just changing the readability of the source code.

Thomas McCabe, who came with the term cyclomatic complexity in 1976, proposed that the cyclomatic complexity of a module should be kept under 10.

I hope it's understandable as I have described it.

Collapse
ronnewcomb profile image
Ron Newcomb

As much as I love my extensions that measure the cc of my functions, there's cases where it goes off the rails. A function with only a switch statement, where every case is a single-line return statement, for example. The "parallelism" of the code makes it easy to follow for humans even if by math it's complex.

I also like things like SonarQube / ReSharper / etc for measuring cc and for the "reduce nesting" auto-refactor which fixes the too-much-indentation issue.

Collapse
arashnrim profile image
Arash

I've never considered refactoring my code differently before, but perhaps this article might change that! My code can definitely be over-indented at times, and I strongly agree with you that it can get a lot more confusing the more indented things get.

Thank you for sharing!