VBScriptを掌握する:構造化エラー管理による「沈黙のバグ」の根絶
VBScriptにおける `On Error Resume Next` は、諸刃の剣ではない。それは単なる「墓場」だ。安易にこれを使い、エラーを無視して処理を継続するコードは、数年後の保守担当者にとっての呪いとなる。
レガシーシステムの最前線に立つ我々にとって、エラーは「隠すもの」ではなく「記録し、解析し、再発を防ぐための資産」であるべきだ。今回は、VBScriptにおける構造化エラー管理の極致、自作エラーハンドラによるスタックトレースの擬似再現術を伝授する。
なぜ標準の Err オブジェクトでは不十分なのか
VBScriptの標準 `Err` オブジェクトは、発生した瞬間に情報を保持するが、`Err.Clear` を呼ぶか、次のエラーが発生した瞬間にその情報は霧散する。関数の呼び出し階層(コールスタック)が深くなるほど、どこで何が起きたのかという「文脈(コンテキスト)」を見失う。
我々が求めるのは、エラー発生の連鎖を保持し、再帰的にスタックを遡行できる堅牢なエラー管理オブジェクトだ。
構造化エラーハンドラ:`ErrorTracker` クラスの実装
以下のコードは、WSH環境においてエラー情報を蓄積し、ログとして出力するためのアーキテクチャである。
‘ ErrorTrackerクラス: エラーコンテキストを保持し、スタックを記録する
Class ErrorTracker
Private m_ErrorQueue
Private Sub Class_Initialize
Set m_ErrorQueue = CreateObject(“Scripting.Dictionary”)
End Sub
‘ エラーの記録(コンテキストの保存)
Public Sub Push(ByVal context, ByVal errObj)
Dim info
info = “Time: ” & Now & vbCrLf & _
“Context: ” & context & vbCrLf & _
“Number: ” & errObj.Number & vbCrLf & _
“Source: ” & errObj.Source & vbCrLf & _
“Description: ” & errObj.Description
‘ 連想配列にスタック順で格納
m_ErrorQueue.Add m_ErrorQueue.Count, info
End Sub
‘ 蓄積された全情報を文字列として取得
Public Function GetStackTrace()
Dim i, result
result = “=== Stack Trace Start ===” & vbCrLf
For i = m_ErrorQueue.Count – 1 To 0 Step -1
result = result & m_ErrorQueue(i) & vbCrLf & “—” & vbCrLf
Next
GetStackTrace = result & “=== Stack Trace End ===”
End Function
Private Sub Class_Terminate
Set m_ErrorQueue = Nothing
End Sub
End Class
実践:エラーの伝播とコンテキストの保持
関数内でエラーが発生した際、即座に終了させるのではなく、呼び出し元へエラーを伝播させつつ、情報を積み上げていく。これが高度な保守性を生む秘訣だ。
Dim tracker : Set tracker = New ErrorTracker
Sub DeepProcess()
On Error Resume Next
‘ 意図的なエラー発生(例: 存在しないオブジェクトの操作)
Dim x : x = 1 / 0
If Err.Number <> 0 Then
tracker.Push “DeepProcess: 算術演算エラー発生”, Err
Err.Raise Err.Number, Err.Source, Err.Description
End If
On Error GoTo 0
End Sub
Sub Main()
On Error Resume Next
DeepProcess
If Err.Number <> 0 Then
tracker.Push “Main: DeepProcessからのエラー捕捉”, Err
WScript.Echo tracker.GetStackTrace()
End If
On Error GoTo 0
‘ 明示的なオブジェクト解放
Set tracker = Nothing
End Sub
Main
シニアエンジニアが守るべき「極限の知見」
1. メモリ管理の鉄則
VBScriptのガベージコレクションは不完全だ。COMオブジェクトを多用する場合、`Set obj = Nothing` を怠れば、大規模なバッチ処理では確実にメモリリークを起こす。特に `Class_Terminate` 内でのオブジェクト解放を徹底せよ。
2. Windows APIの活用とリスク
WSHから `WScript.Shell` 経由でWin32 APIを叩く際は、必ず `On Error Resume Next` のスコープを最小限に絞れ。API呼び出しはOSのメモリ空間に直接干渉する。スタックトレースを記録する際、APIの戻り値(LastError)を自前で取得し、`Err.Number` と突き合わせるのがプロの作法だ。
3. レガシー環境における生存戦略
現代のWeb API連携全盛の時代にあっても、この構造化エラー管理は有効だ。JSON形式でログを吐き出せば、後段のSplunkやELKスタックへの取り込みも容易になる。VBScriptを「古い言語」と蔑むか、「システムを堅牢に支える基盤」と捉えるか。その差が、エンジニアとしての格を決める。
結びに代えて
エラーを隠すコードは、自らの首を絞める行為に等しい。エラー情報を構造化し、スタックトレースを可視化することは、システムに対する誠実さそのものである。
次に貴方が書くスクリプトには、ぜひこの「コンテキストを保存する魂」を込めてほしい。沈黙するシステムではなく、語りかけてくるシステムこそが、真に保守可能なアーキテクチャである。
