【テクニカル・上級編】【プロフェッショナル向け】Project VBAでのクラスモジュール設計による「タスク管理エンジン」の構築 – Project VBA解析バイブル

スポンサーリンク

【Project VBA】レガシーを凌駕する:クラスモジュールによる「タスク管理エンジン」の再構築

プロジェクト管理の世界において、VBAというツールは時として「呪われた遺物」のように扱われる。しかし、それは言語の限界ではない。設計者の怠慢によるものだ。

君たちがこれまで書いてきた、標準モジュールにグローバル変数を散りばめ、`ActiveProject`に依存しきった脆弱なコードは、今日で終わりにする。真に堅牢な「タスク管理エンジン」を構築するためには、Projectオブジェクトを抽象化し、メモリのライフサイクルを制御するアーキテクチャが不可欠だ。

1. なぜ「標準モジュール」は悪なのか

標準モジュールによる手続き型プログラミングは、小規模な自動化には適している。だが、数百のタスクを操作し、外部APIと連携し、複雑な依存関係を解くようなシステムにおいて、それは「技術的負債の製造装置」と化す。

我々が目指すのは、「Taskオブジェクトの抽象化」だ。Projectの`Task`オブジェクトは、それ自体がメモリを消費する巨大な構造体である。これを生のまま操作するのではなく、独自の「TaskControllerクラス」でラップし、アクセスを制限(カプセル化)することで、予期せぬメモリリークや、参照の不整合を防ぐ。

2. クラス設計:TaskWrapperによるカプセル化

まずは、Taskオブジェクトの操作を抽象化するクラスを作成する。ここで重要なのは、VBAのガベージコレクションを信用しないことだ。

TaskWrapper.cls (抜粋)

‘ @Description: Taskオブジェクトのラッパー。直接的なアクセスを制御し、安全性を担保する。
Option Explicit

Private pTask As MSProject.Task

‘ コンストラクタでTaskを注入(DIパターン)
Public Sub Initialize(ByRef targetTask As MSProject.Task)
Set pTask = targetTask
End Sub

‘ プロパティの抽象化
Public Property Get Name() As String
Name = pTask.Name
End Property

‘ メモリ最適化:オブジェクトの解放を明示的に行う
Private Sub Class_Terminate()
Set pTask = Nothing
End Sub

このクラスを基盤に、タスクのバリデーションやステータス更新をメソッドとして実装する。これにより、コードの再利用性が飛躍的に向上する。

3. Windows APIによるメモリとパフォーマンスの制御

大規模なProjectファイル(数千タスク規模)を扱う際、VBAのループは遅い。特にUI更新が走ると地獄だ。ここで、`Application.ScreenUpdating`だけでなく、Windows APIを駆使してプロセスの優先度やメモリ状態を監視する設計が必要になる。

例えば、大量のタスクを更新する際、一時的に`Sleep`関数を挟んでシステムのリソースを解放するテクニックは、レガシー環境でのクラッシュを防ぐ定石だ。

If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If

‘ 大量更新時のバッファリング
Public Sub BatchUpdate(tasks As Collection)
Dim t As Variant
For Each t In tasks
‘ ここでタスクの処理
‘ システムの負荷を見ながら、必要に応じてスリープを挟む
If Timer Mod 10 = 0 Then DoEvents: Sleep 10
Next t
End Sub

4. プロフェッショナルなリソース管理:破滅を回避するために

VBAにおいて「メモリリーク」は、特にオブジェクト型の変数で頻発する。`Set obj = Nothing`を書き忘れることは、戦場において銃の安全装置をかけ忘れることと同義だ。

私が構築するエンジンでは、すべてのプロセスを以下のパターンで管理する。

1. Factoryパターンによる生成: `CreateTaskController`メソッドでインスタンスを払い出す。
2. Usingクリーンアップ: すべてのプロシージャは、`Cleanup`ラベルによる終了処理を徹底する。

Public Sub ProcessProjectTasks()
Dim engine As TaskController
On Error GoTo Cleanup

Set engine = New TaskController
‘ ロジック実行…

Cleanup:
‘ 明示的なオブジェクト解放とエラーハンドリング
If Not engine Is Nothing Then Set engine = Nothing
If Err.Number <> 0 Then MsgBox “Critical Error: ” & Err.Description
End Sub

5. 伝説のアーキテクトからの助言

君たちが構築するシステムは、3年後、5年後に別の誰かが触ることになる。その時、コードが「なぜそう書かれたのか」を説明できるのは、設計思想だけだ。

  • API連携の最適化: JSONのパースにはVBAの標準機能ではなく、`ScriptControl`や`WinHttp`を利用し、Projectのメモリ空間とは切り離して処理せよ。
  • レガシーの許容: 古いプロジェクトファイル形式(.mpp)と最新の環境が混在する場合、`Application.Version`で条件分岐を行い、オブジェクトのキャストを厳格に行うこと。

VBAは、決して非力な言語ではない。使い手の設計力次第で、エンタープライズ級のタスク管理エンジンに化ける。

コードを書き殴るな。「設計を積み上げろ」。

次のステージで、君たちの洗練されたコードに会えることを期待している。

タイトルとURLをコピーしました