Files
claudeskill/skills/vba-best-practices/SKILL.md
Misaka_Company 3c073b73e2 Add guidance on duplicate Dim declarations in VBA
Clarify that VBA uses procedure-level scope and declaring the same variable more than once causes compile errors. Include examples of correct and incorrect patterns.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-27 13:37:20 +08:00

6.4 KiB

name, description
name description
vba-best-practices VBA (Visual Basic for Applications) coding standards for Excel, Word, and Office automation. Trigger this skill when the user asks for help writing or reviewing VBA macros, wants to improve code quality, or shares VBA code asking "is this good?" or "how can I improve this?"

VBA Best Practices

Code Structure

Always start every module with Option Explicit — forces explicit variable declaration, catches typos at compile time. Enable globally via Tools > Options > Editor > "Require Variable Declaration".

Declare variables at the top of each procedure, one per line, with descriptive names. Avoid single letters (i, j) and reserved words.

Naming conventions:

  • Subs/Functions → PascalCase
  • Local variables → Hungarian prefix (iCount, sName, bFlag)
  • Module-level → PascalCase; globals prefix with g_
  • Constants → ALL_CAPITALS; helper functions prefix with fn/fx

Indent with tabs. Everything inside loops, conditionals, and With blocks gets one level deeper.


Variables & Data Types

  • Avoid Variant — it's 16 bytes and slow. Use it only when the type is genuinely unknown or when passing arrays of mixed types.
  • Never use Option Base 1 — keep the default array base of 0.
  • Never use Option Compare Text — keep string comparisons case-sensitive by default.
  • Use vbNullString instead of "" for empty string assignment; use Len(s) = 0 to check emptiness — both are faster than comparing against "".
  • Use vb string constants instead of Chr() calls: vbTab, vbLf, vbCr, vbNewLine (fastest), vbNullChar.

No Duplicate Dim Declarations Within a Procedure

VBA uses procedure-level scope — a variable declared anywhere inside a Sub/Function is scoped to the entire procedure. Declaring the same variable name more than once (even in separate If/Else branches or nested loops) causes a compile error.

Rule: declare every variable exactly once, at the top of the procedure.

' ❌ Compile error — same name declared twice in different branches
Sub BadExample()
    If condition Then
        Dim x As Integer   ' first declaration
        x = 1
    Else
        Dim x As Integer   ' DUPLICATE — compiler rejects this
        x = 2
    End If
End Sub

' ✅ Correct — declared once at the top, assigned freely in any branch
Sub GoodExample()
    Dim x As Integer       ' single declaration

    If condition Then
        x = 1
    Else
        x = 2
    End If
End Sub

The same rule applies to loop variables reused across multiple For Each loops:

' ❌ Compile error — rawMat declared inside two separate loops
For Each rawMat In rawMaterials        ' implicit Dim inside loop
    allRawMaterials.Add rawMat
Next rawMat

For Each rawMat In allRawMaterials     ' duplicate Dim — compile error
    ' ...
Next rawMat

' ✅ Correct — declare once at the top, reuse freely
Dim rawMat As Variant

For Each rawMat In rawMaterials
    allRawMaterials.Add rawMat
Next rawMat

For Each rawMat In allRawMaterials
    ' ...
Next rawMat

Tip: A quick way to catch duplicates is to search for Dim <varname> within the same procedure. With Option Explicit enabled, the compiler will also surface this error on the first compile attempt.


Parameters & Scope

  • Always declare ByVal or ByRef explicitly — VBA defaults to ByRef, which can cause silent side effects. Use ByVal unless you intentionally need to modify and return the argument.
  • Minimize global variables. Use Public/Private at module level (not Global/bare Dim). If a global is unavoidable, prefix with g_.
  • Validate arguments at the top of every Sub/Function before using them.

Error Handling

Never use On Error Resume Next — it silently swallows bugs. Instead, add a custom error handler to every procedure:

Sub DoSomething()
    On Error GoTo ErrorHandler
    ' ... code ...
    Exit Sub
ErrorHandler:
    Debug.Print "Error in DoSomething: " & Err.Description
    ' Log, re-raise, or recover as appropriate
End Sub

Handle the error in the same procedure where it occurs.


Control Flow & Objects

  • No GoTo for program logic — use If/ElseIf, Select Case, and loops. (GoTo ErrorHandler is the one accepted exception.)
  • Use With … End With whenever you reference the same object more than once — fewer dot-lookups means faster execution:
With ws.Range("A1").Font
    .Bold = True
    .Size = 12
End With
  • Never reference ActiveCell, ActiveSheet, or ActiveWorkbook — always bind to explicit object variables:
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Data")
ws.Range("A1").Value = "Hello"
  • Use built-in constants and enumerations with full prefix (VBA.vbMsgBoxResult.vbYes, msoFileType.msoFileTypeExcelWorkbooks) for readability and IntelliSense support. Group related custom constants into Enum blocks.

Performance

  • Bulk data via arrays — read a range into an array, process in memory, write back in one shot. Never loop over individual cells for large datasets:
Dim arData As Variant
arData = Sheet1.Range("A1:D500").Value   ' one read
' ... process arData() in memory ...
Sheet1.Range("A1:D500").Value = arData   ' one write
  • ReDim Preserve inside a loop is forbidden. Oversize the array upfront; ReDim (without Preserve) once at the end if needed.
  • Minimize Application.ScreenUpdating = False — use only when necessary, and always restore it (including inside error handlers).

Quick Checklist

Rule Why it matters
Option Explicit in every module Prevents undeclared-variable bugs
Descriptive names + Hungarian prefixes Readability & self-documentation
Each variable declared once, at procedure top Duplicate Dim = compile error
ByVal/ByRef always explicit No silent side effects
Custom GoTo ErrorHandler, not Resume Next Errors surface instead of hiding
With…End With for repeated object refs Speed + clarity
No ActiveCell/ActiveSheet/ActiveWorkbook Robust against user selections
vbNullString / Len() for strings Faster than "" comparison
Arrays for bulk range I/O Orders-of-magnitude speed gain
No Option Base 1 or Option Compare Text Predictable defaults
No GoTo except for error handler label Structured, readable flow