SolidWorks VBAの「負の遺産」を殲滅せよ:Onionレイヤー構造による堅牢なクラス設計術
SolidWorks VBAの現場で、未だに `On Error Resume Next` が幅を利かせていないだろうか。
「とりあえず動けばいい」という考えで作られたスパゲッティコードは、数年後の自分やチームを確実に殺す。フィーチャ操作の失敗を握りつぶし、不正なオブジェクト状態でメモリを浪費し続けるマクロは、エンジニアリングツールではなく「爆弾」だ。
今日は、レガシーなマクロを、メンテナンス可能な「エンタープライズ級」の構造へ昇華させるための、Onion(オニオン)レイヤー設計と現代的なエラーハンドリングの極意を授ける。
—
1. なぜ「On Error Resume Next」が罪深いのか
多くのVBAマクロが陥る罠は、エラーを無視することで「予期せぬ状態」を放置することだ。SolidWorks APIは、COMオブジェクトの寿命(LifeCycle)管理が非常にシビアだ。
フィーチャ生成に失敗した際、適当なリトライや無視を行うと、SolidWorksの内部メモリに「ゾンビ化した未定義フィーチャ」が残り、後の処理で`Access Violation`を引き起こす。エラーは隠蔽するのではなく、制御可能な形に変換し、適切に破棄(Dispose)しなければならない。
—
2. Onionレイヤー構造への転換
堅牢なマクロを作るには、責務を分離する。これがOnion構造の基本だ。
1. Core Layer (Domain): SolidWorks APIとの直接的な対話のみを行う。
2. Service Layer (Business Logic): 生成・編集の順序や条件を制御する。
3. UI/Entry Layer (Presentation): ユーザーインターフェースとエラー表示を行う。
これにより、ビジネスロジックを修正したいときに、APIの呼び出し手順まで書き換えるという「悲劇」を回避できる。
—
3. 実践:保守性の高いフィーチャ生成クラス
まずは、APIの複雑さを隠蔽するクラスモジュール `PartManager` の設計例を見てほしい。
‘ クラス名: PartManager
Option Explicit
Private swApp As SldWorks.SldWorks
Private swModel As SldWorks.ModelDoc2
‘ 初期化時にアプリケーションオブジェクトを注入(Dependency Injection)
Public Sub Initialize(ByRef app As SldWorks.SldWorks)
Set swApp = app
End Sub
‘ 堅牢なフィーチャ作成メソッド
Public Sub CreateExtrude(depth As Double)
‘ 構造化エラーハンドリング
On Error GoTo ErrorHandler
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then Err.Raise 1001, “PartManager”, “ドキュメントが開かれていません”
‘ API操作の実行
Dim swFeature As SldWorks.Feature
Set swFeature = swModel.FeatureManager.FeatureExtrusion2(…)
If swFeature Is Nothing Then Err.Raise 1002, “PartManager”, “フィーチャ生成に失敗しました”
Exit Sub
ErrorHandler:
‘ ここでログ出力やクリーンアップを行う
Debug.Print “Error ” & Err.Number & “: ” & Err.Description
Err.Raise Err.Number, “PartManager”, Err.Description
End Sub
この設計のポイント:
- エラーの伝播: `On Error Resume Next` で逃げず、`Err.Raise` で呼び出し元に問題を通知する。
- ガード節: `If swModel Is Nothing` のように、処理の前提条件を冒頭でチェックする。
- 単一責任: このクラスは「生成する」ことだけに集中する。
—
4. 現代的なエラーハンドリングとリソース解放
SolidWorks APIを使用する際、最も注意すべきは「オブジェクトの破棄」だ。VBAには明示的な `Dispose` はないが、`Set = Nothing` を確実に行うことで、COM参照カウントを適切に管理できる。
Public Sub SafeExecute()
Dim mgr As New PartManager
On Error GoTo Finalize
mgr.Initialize Application.SldWorks
mgr.CreateExtrude 0.05
Finalize:
‘ 異常終了時でも確実にリソースをクリーンアップ
Set mgr = Nothing
If Err.Number <> 0 Then
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical
End If
End Sub
—
5. データベース連携時の黄金律
設計担当者がやりがちなのは、フィーチャ生成ループの中でDB接続を維持することだ。これは論外である。
1. データ取得: DBから必要なパラメータをすべてメモリ(配列やコレクション)に読み込む。
2. クローズ: DB接続を即座に切断する。
3. 生成: SolidWorksの操作を行う。
4. 結果保存: 最後に一度だけ接続して結果を書き込む。
SolidWorksが重い処理を行っている最中にDB接続がタイムアウトするリスクを排除せよ。
—
最後に:伝説のエンジニアとしてのアドバイス
「動くコード」を作るのは新米の仕事だ。「壊れないコード」を作り、「壊れたときに原因が即座にわかるコード」を書くのが、我々アーキテクトの仕事である。
今回紹介したクラス化と構造化エラーハンドリングは、最初の構築には手間がかかる。だが、その手間は、将来の数千時間に及ぶ「原因不明のバグ調査」を未然に防ぐための強力な投資だ。
明日からの開発では、`On Error Resume Next` をタイプする指を止め、まずはクラス図を書くことから始めてほしい。あなたのコードが、現場の資産となることを期待している。
