Project VBAを掌握せよ:タスク依存関係の「ラグタイム」を制する極限の自動化術
Project VBAの深淵に触れたことがある諸君なら知っているはずだ。GUI上のマウス操作でタスクの依存関係を一つ一つ調整することが、どれほど無益で、かつバグの温床となるかを。
特に「ラグタイム」の一括操作は、プロジェクトの遅延リスクをシミュレートする際に必須の武器となる。だが、MS Projectのオブジェクトモデルは、時としてメモリを食い荒らし、大規模な計画表では平然とハングアップを引き起こす。
本稿では、シニアエンジニアが現場で即座に展開できる、「ラグタイム一括最適化エンジン」の実装指針を授ける。
—
1. なぜ「標準機能」では足りないのか
Projectのタスクリンク(TaskDependencies)は、一見単純なコレクションに見える。しかし、内部的には複雑な再計算エンジンと紐付いており、単なるループ処理でラグタイムを書き換えるのは、データベースの整合性を自ら破壊する行為に等しい。
我々が目指すべきは、「メモリリークを皆無にし、再計算プロセスを最小化する」ことだ。VBAのガベージコレクションは信用するな。オブジェクトは自らの手で殺す(解放する)のが鉄則である。
—
2. 実装:ラグタイム一括調整ツール(Core Engine)
以下のコードは、全タスクのFS(終了-開始)関係に対し、指定したラグタイムを一括適用するプロシージャだ。
Option Explicit
‘ 依存関係の調整用メインモジュール
Public Sub BatchUpdateLagTime(ByVal targetLagDays As Double)
Dim proj As Project
Dim task As task
Dim link As taskDependency
Set proj = ActiveProject
‘ プロジェクトの再計算を抑制してパフォーマンスを最大化
Application.Calculation = pjManual
On Error GoTo Cleanup
For Each task In proj.Tasks
If Not task Is Nothing Then
For Each link In task.TaskDependencies
‘ 依存関係がFS(Finish-to-Start)の場合のみラグタイムを調整
If link.Type = pjFinishToStart Then
‘ ラグタイムはProject内部では「分」単位で保持される
‘ 1日 = 480分(環境により調整)
link.Lag = targetLagDays 480 & “m”
End If
Next link
End If
‘ メモリ解放の明示的介入(大規模プロジェクトでのGC安定化)
Set link = Nothing
Next task
Cleanup:
‘ 最後に再計算を実行し整合性を確保
Application.Calculation = pjAutomatic
Application.CalculateAll
Set task = Nothing
Set proj = Nothing
If Err.Number <> 0 Then
MsgBox “Critical Error: ” & Err.Description, vbCritical
End If
End Sub
—
3. シニアエンジニアのための最適化の知見
メモリとライフサイクル
上記のコードで `Set task = Nothing` をループ内で行うのは、VBAの参照カウンタを確実にデクリメントし、大規模なWBS(数千タスク)を扱う際のメモリスタック溢れを防止するためだ。`For Each` ループ内でオブジェクトが生成され続ける設計は、Project VBAにおいては死を意味する。
再計算の制御(Calculation Mode)
`Application.Calculation = pjManual` を使用せよ。これを怠ると、リンクを1つ書き換えるたびにProjectは全タスクのクリティカルパスを再計算しようと試みる。数千のリンクを持つファイルでこれをやれば、処理時間は指数関数的に増大する。変更を全てコミットした後に `CalculateAll` を叩くのが、プロの作法だ。
Windows APIによる「強制終了」の検知(応用編)
もし、非常に重いProjectファイルを扱うなら、Windows API `GetTickCount` や `Sleep` を利用して、処理中のUIフリーズを回避しつつ、タスクの進捗状況をステータスバーに表示させるべきだ。
‘ ステータスバー更新の定石
Application.StatusBar = “Processing Task ID: ” & task.ID
DoEvents ‘ UIスレッドを解放する
—
4. 現場への提言:レガシーとの共存
このスクリプトは、単なる便利ツールではない。プロジェクト管理における「仮説検証」のスピードを上げるためのツールだ。
- リスク管理: 「もし納期が全工程で2日遅れたら?」というシミュレーションが数秒で終わる環境を構築せよ。
- 保守性: 本コードは汎用性を高めるため、定数(480分)をプロジェクトの作業時間カレンダーから取得する関数へと拡張することを推奨する。
我々はツールに振り回される存在ではない。ツールを定義し、プロジェクトの複雑性を制御するアーキテクトである。このコードをベースに、諸君の現場における「最適解」を構築してほしい。
コードは嘘をつかない。だが、最適化の意識を欠いたコードは必ず現場を殺す。
次回の講義では、ProjectとExcel間での「差分同期」を、ADOを用いた高速化アプローチで深掘りする。期待しておけ。
