Add VBA best practices skill
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
114
skills/vba-best-practices/SKILL.md
Normal file
114
skills/vba-best-practices/SKILL.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
name: vba-best-practices
|
||||||
|
description: 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`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
```vb
|
||||||
|
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:
|
||||||
|
|
||||||
|
```vb
|
||||||
|
With ws.Range("A1").Font
|
||||||
|
.Bold = True
|
||||||
|
.Size = 12
|
||||||
|
End With
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Never reference `ActiveCell`, `ActiveSheet`, or `ActiveWorkbook`** — always bind to explicit object variables:
|
||||||
|
|
||||||
|
```vb
|
||||||
|
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:
|
||||||
|
|
||||||
|
```vb
|
||||||
|
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 |
|
||||||
|
| `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 |
|
||||||
Reference in New Issue
Block a user