Project VBAを掌握せよ:先行タスクの再帰解析で「プロジェクトの急所」を可視化する
プロジェクトマネジメントの世界において、WBSは単なるタスクリストではない。それは「依存関係という名の蜘蛛の巣」である。
多くのVBAエンジニアが、`Task.Predecessors`プロパティを単に文字列として取得し、満足して終わる。だが、真のアーキテクトはそこから先を見る。先行タスクを再帰的に辿り、クリティカルパスのボトルネックを特定し、プロジェクトの「遅延の連鎖」を未然に防ぐ。
今日は、MS Project VBAで「依存関係の迷宮」を解き明かすための、堅牢かつ実務的な実装術を伝授しよう。
—
1. なぜ「単純なループ」では破綻するのか
多くの者が陥る罠は、`Predecessors`プロパティが返す文字列(例: “3FS+2d, 5SS”)を力任せにSplit関数でパースしようとすることだ。
Project VBAにおいて、依存関係解析の設計で最も重要なのは以下の3点である。
1. データの正規化: `TaskDependencies`オブジェクトを使用せよ。文字列解析は脆弱性の温床だ。
2. 再帰の深さ管理: 複雑なプロジェクトでは循環参照やスタックオーバーフローのリスクがある。再帰の深さを制限し、訪問済みタスクを記録(Dictionary等でキャッシュ)する設計が必須となる。
3. オブジェクトの生存期間: `ActiveProject`に直接アクセスするコードを関数内に散らばらせるな。オブジェクトを引数で渡し、メモリリークを避けるのがプロの流儀だ。
—
2. 実装:依存関係を再帰的に抽出するエンジン
以下に、特定のタスクから「先祖(先行タスク)」を辿り、依存関係の深さとIDを抽出する堅牢なコードを提示する。
Option Explicit
‘ 依存関係を格納する自作クラス(Dictionary等で管理することを想定)
‘ 開発現場では、この結果をExcelに書き出し、ネットワーク図を描画する前段として使用する
Public Sub AnalyzeDependencies(ByVal targetTask As Task)
Dim visited As Object
Set visited = CreateObject(“Scripting.Dictionary”)
Debug.Print “— 解析開始: タスクID ” & targetTask.ID & ” —”
RecursiveTrace targetTask, 0, visited
End Sub
Private Sub RecursiveTrace(ByVal t As Task, ByVal depth As Long, ByRef visited As Object)
‘ 循環参照防止とパフォーマンスのためのキャッシュチェック
If visited.Exists(t.UniqueID) Then Exit Sub
visited.Add t.UniqueID, t.Name
‘ 深さ制限(例: 20階層を超えたら解析停止など、安全策を講じる)
If depth > 20 Then Exit Sub
Dim dep As TaskDependency
For Each dep In t.TaskDependencies
‘ 先行タスク(From)を取得
Dim predecessor As Task
Set predecessor = dep.From
‘ コンソールに出力(実務では配列やコレクションへ格納し、Excelへ出力する)
Debug.Print String(depth, ” “) & “-> ID:” & predecessor.ID & ” [” & predecessor.Name & “]”
‘ 再帰呼び出し
RecursiveTrace predecessor, depth + 1, visited
Next dep
End Sub
—
3. 現場で生き残るための設計上の注意点
A. データベース連携の最適化
もしこの解析結果をSQL ServerやAccessに送る場合、VBA上で逐次レコードセットを操作してはいけない。「解析結果を二次元配列に格納し、最後にバッチでバルクインサートする」。これがネットワーク負荷を抑え、ツールを高速化する鉄則だ。
B. エラーハンドリングの防壁
`TaskDependencies`は、削除されたタスクや、外部プロジェクトへのリンクが含まれると予期せぬ挙動を示すことがある。
- `On Error Resume Next` で逃げるのは三流。
- `If Not dep.From Is Nothing Then` といった明示的なNullチェックをループ内に配置せよ。
C. メンテナンス性の担保
マジックナンバー(例: 深さ制限の20)は定数としてモジュールの冒頭で定義すること。また、解析ロジックと出力ロジックをクラスモジュールで分離すれば、将来的に「Excelへの出力」から「Web APIを通じた可視化ツールへの連携」へ移行する際も、コードを書き直す必要はない。
—
最後に:なぜあなたがこれをやるのか
自動化ツールとは、単に作業を楽にするものではない。「人間が見落とす複雑な依存関係の連鎖」を可視化し、リスクを先回りして潰すための意思決定エンジンである。
「先行タスクが多い=責任の所在が曖昧」あるいは「依存関係が多すぎて動かせない」といったボトルネックは、コードを実行した瞬間に可視化される。その時、あなたは単なるVBAエンジニアではなく、プロジェクトの行く末を照らす「ナビゲーター」になっているはずだ。
さあ、蜘蛛の巣を解き明かせ。それが、我々エンジニアに与えられた責務だ。
