All About Indenting

Do you obsess over the smallest details of the code-writing process? If not, you might want to skip this article. Don't say I didn't warn you...

All About Indenting

Today's article is a quick practical tip about the code-writing process.

Proper indenting is one of the most important parts of creating readable code.  Each logical "block" of code should be indented to distinguish it from the code that comes before and after it.  Code blocks are often nested, leading to multiple levels of indentation.

Here's a quick example:

'Contrived routine that lists all the code modules
'   in the current project and whether or not
'   they are open in the VBA IDE
Sub ListModules()
    With CurrentProject
        Dim AccObj As AccessObject
        For Each AccObj In .AllModules
            If AccObj.IsLoaded Then
                Debug.Print AccObj.Name; " is loaded"
            Else
                Debug.Print AccObj.Name; " is not loaded"
            End If
        Next AccObj
    End With
End Sub

The above code has four blocks.  From the outside in, they are:

  • Sub ... End Sub
  • With ... End With
  • For Each ... Next
  • If ... Else ... End If

When I write code with these sorts of blocks, I use the following approach:

  1. Write the opening line
  2. Press [Enter] twice
  3. Write the closing line
  4. Press [Up] then [Tab]
  5. Write the inner code

Practical Example

Here's how the above code would evolve in my development environment.  (I use the pipe character [|] in the code samples below to represent the position of the cursor.)

Detailed Breakdown of the First Block

Sub ListModules()
    With CurrentProject|
End Sub
1. Write the opening line
Sub ListModules()
    With CurrentProject
    
    |
End Sub
2. Press [Enter] twice
Sub ListModules()
    With CurrentProject
        
    End With|
End Sub
3. Write the closing line
Sub ListModules()
    With CurrentProject
        |
    End With
End Sub
4. Press [Up] then [Tab]
Sub ListModules()
    With CurrentProject
        Dim AccObj As AccessObject|        
    End With
End Sub
5. Write the inner code

Block-by-Block Overview

Sub ListModules()
    |
End Sub
Start with the subroutine block
Sub ListModules()
    With CurrentProject
        |
    End With
End Sub
Add the With ... End With block
Sub ListModules()
    With CurrentProject
        Dim AccObj As AccessObject
        For Each AccObj In .AllModules
            |
        Next AccObj
    End With
End Sub
Add the For Each ... Next block
Sub ListModules()
    With CurrentProject
        Dim AccObj As AccessObject
        For Each AccObj In .AllModules
            If AccObj.IsLoaded Then
                |
            End If
        Next AccObj
    End With
End Sub
Add the If ... End If block
Sub ListModules()
    With CurrentProject
        Dim AccObj As AccessObject
        For Each AccObj In .AllModules
            If AccObj.IsLoaded Then
                Debug.Print AccObj.Name; " is loaded"
            Else
                Debug.Print AccObj.Name; " is not loaded"
            End If
        Next AccObj
    End With
End Sub
Finish populating the If ... Else ... End If block

Why Do I Do It This Way?

This approach helps reduce compile errors, but that in itself is not a big deal.  Compile errors are cheap and easy to fix.

Where this approach helps the most is in avoiding off-by-one type logic errors, such as ensuring a variable is being incremented on the correct side of a loop.  This is important, as logic errors are the most difficult and expensive bugs to fix.

(That said, the best way to write code that's easy to read and to avoid block-related logic errors is to minimize the number of indented levels in your code in the first place.  For example, if you have a procedure with six levels of indentation, you can probably split the three inner code blocks out into a standalone procedure and cut your levels of indentation in half.)

Reader Feedback

I assume that most developers use this approach, but I could be wrong.  

Newer development environments (i.e., not VBA) often have a code-block-autocomplete feature built-in or available via third-party plugins.  Thus, this might be a problem somewhat unique to VBA in the year of our Lord 2023.

Do you use a similar approach when writing code in VBA?  If not, what approach do you use?  Or do you not really think about it?  Maybe I'm just a weirdo for obsessing over this level of programming minutiae.  Let me know in the comments below.


Referenced articles

Some Bugs are Better than Others
Not all bugs are created equal. Avoid the expensive ones by making more of the ones that are easy to find and fix.

All original code samples by Mike Wolfe are licensed under CC BY 4.0