Project VBAを掌握せよ:クラスモジュールで構築する「タスク管理エンジン」の極意
VBAでProjectを操作する際、多くの開発者が陥る罠がある。それは、標準モジュールに`ActiveProject.Tasks(…)`を直接書き殴り、スパゲッティコードを生み出すことだ。
「とりあえず動く」コードは、プロジェクトが複雑化した瞬間に破綻する。進捗計算、バリデーション、外部データとの同期……これらをすべて標準モジュールに詰め込めば、それはもはや「管理」ではなく「苦行」だ。
今日は、VBAにおける「クラスモジュール」を用いたタスク管理エンジンの設計思想を伝授する。これができれば、君のツールはただのスクリプトから、堅牢な「業務基盤」へと進化する。
—
なぜ「生」のTaskオブジェクトを直接触ってはいけないのか
Projectの`Task`オブジェクトは強力だが、そのままでは「裸のデータ」に過ぎない。
- 誰が触っても進捗率を150%に書き換えられる。
- 依存関係の整合性を保つロジックが散逸する。
- ファイルの読み書き時にエラーハンドリングが漏れる。
我々エンジニアが目指すべきは、「ロジックのカプセル化」だ。Taskをクラスでラップし、そのインスタンスを通じてのみ操作を許可することで、バグを未然に排除する。
—
設計の核心:TaskWrapperクラスの実装
まずは、タスクを操作するための「エンジン」となるクラスモジュール(`clsTaskEngine`と命名)を作成しよう。
実装コード例
‘ クラスモジュール: clsTaskEngine
Option Explicit
Private pTask As MSProject.Task
‘ コンストラクタ代わりの初期化メソッド
Public Sub Initialize(ByVal targetTask As MSProject.Task)
Set pTask = targetTask
End Sub
‘ プロパティ: 進捗率の安全な更新(バリデーションを内包)
Public Property Let Progress(ByVal value As Integer)
If value < 0 Or value > 100 Then
Err.Raise vbObjectError + 1001, , “進捗率は0から100の間で指定してください。”
End If
pTask.PercentComplete = value
End Property
‘ ビジネスロジック: タスクの状態を判定
Public Property Get Status() As String
If pTask.PercentComplete = 100 Then
Status = “完了”
ElseIf pTask.Start > Now Then
Status = “未着手”
Else
Status = “進行中”
End If
End Property
‘ バリデーション: 独自の業務ルールを適用
Public Function ValidateTask() As Boolean
‘ 例:名前が空ならエラー
If Len(pTask.Name) = 0 Then
ValidateTask = False
Exit Function
End If
ValidateTask = True
End Function
—
現場で差がつく「運用」のポイント
1. インスタンスのライフサイクル管理
標準モジュールで`Dim t As New clsTaskEngine`を乱発してはいけない。ProjectのタスクIDは変更される可能性がある。常に`TaskID`をキーにして、必要に応じてインスタンスを生成・破棄するサイクルを徹底すること。
2. 外部データ(Excel/DB)との連携
Projectのタスクを更新する際は、必ず「トランザクション的な視点」を持つこと。
外部ソースからデータを流し込む際は、以下の順序を厳守する:
1. Validation: クラスメソッドで値の正当性を確認。
2. Update: クラスのプロパティを通じて更新。
3. Commit: 最後に`Application.CalculateAll`を呼び出し、スケジュールを確定させる。
3. エラーハンドリングの構造化
標準モジュール側で`On Error GoTo`を多用するのは過去の遺物だ。クラス側で独自のエラーを投げ、呼び出し元でそれをキャッチする。この設計により、どこでビジネスルールが破られたのかが明確になる。
—
呼び出し側(標準モジュール)のスマートな書き方
Sub UpdateTaskProgressExample()
Dim t As MSProject.Task
Dim engine As clsTaskEngine
Set t = ActiveProject.Tasks(1)
Set engine = New clsTaskEngine
‘ クラスを介して操作
engine.Initialize t
On Error Resume Next
engine.Progress = 120 ‘ ここでバリデーションエラーが発生
If Err.Number <> 0 Then
MsgBox “エラー発生: ” & Err.Description
End If
On Error GoTo 0
End Sub
—
結論:コードを「資産」に変えろ
クラスモジュールを導入することは、一見するとコード量が増え、面倒に感じるかもしれない。しかし、半年後に君自身がそのコードを改修する時、あるいは他のメンバーに引き継ぐ時、この設計が「最強の防波堤」であることに気づくだけだ。
VBAは、書き方一つで「使い捨ての道具」にもなれば、「業務を支える基盤」にもなる。
さあ、君のプロジェクトにこの「タスク管理エンジン」を組み込み、混沌としたタスク管理から卒業しよう。
技術に妥協するな。それがエンジニアとしての矜持だ。
