依存関係の「動的マッピング」:IDなき世界でタスクを結ぶためのアーキテクチャ
現場のCSVデータは常に汚れている。プロジェクトマネージャーがExcelで書き殴ったタスクリストには、一意なIDなど振られていないことがほとんどだ。彼らは「名前」でタスクを管理し、人間同士のコンテキストで依存関係を維持している。
我々エンジニアがやるべきは、その曖昧な世界に堅牢な構造を強制することだ。Project VBAにおいて、タスク名をキーにして依存関係を再構築するロジックは、自動化の「正念場」と言える。単なるループ処理で済ませれば、プロジェクト規模が肥大化した瞬間にメモリは死ぬ。
今日は、その泥臭い現場で生き残るための「動的マッピング」の実装思想を授ける。
—
1. 高速化の核心:Dictionaryオブジェクトによるルックアップテーブル
数千行のタスクに対して、毎回 `Project.Tasks` をスキャンして `Find` メソッドを叩くのは愚行だ。計算量は $O(n^2)$ に達し、処理は遅延する。
まず、メモリ上に「名前とタスクIDの対応表(ハッシュマップ)」を構築する。`Scripting.Dictionary` を使い、メモリ内検索を $O(1)$ に収めるのが、アーキテクトとしての最低限の流儀だ。
2. 実装:動的リンク生成ロジック
以下に、先行タスク名からIDを逆引きし、`Task.TaskDependencies` を構築する堅牢な実装を示す。
‘ 必要な参照設定: Microsoft Scripting Runtime
Option Explicit
Public Sub ImportDependenciesFromCSV(ByVal csvPath As String)
Dim pj As Project
Set pj = ActiveProject
‘ メモリ上にタスク名とIDのマップを作成
Dim taskMap As Object
Set taskMap = CreateObject(“Scripting.Dictionary”)
Dim t As Task
For Each t In pj.Tasks
If Not t Is Nothing Then
If Not taskMap.Exists(t.Name) Then
taskMap.Add t.Name, t.ID
End If
End If
Next t
‘ CSV解析ロジック(簡略化のため、ここではCSVから「タスク名」と「先行タスク名」を取得していると仮定)
‘ 実務ではここを FileSystemObject でストリーム読み込みすること
Dim targetTaskName As String, predecessorName As String
‘ ループ開始
‘ … (CSV読み込み処理) …
‘ 依存関係の構築
If taskMap.Exists(targetTaskName) And taskMap.Exists(predecessorName) Then
Dim targetID As Long, preID As Long
targetID = taskMap(targetTaskName)
preID = taskMap(predecessorName)
‘ リンク構築: TaskDependencies.Add(PredecessorTask)
‘ 循環参照チェックを怠るとProject自体がクラッシュするため、例外ハンドリングは必須
On Error Resume Next
pj.Tasks(targetID).TaskDependencies.Add pj.Tasks(preID)
If Err.Number <> 0 Then
Debug.Print “リンク作成失敗: ” & targetTaskName & ” <- " & predecessorName
End If
On Error GoTo 0
End If
' クリーンアップ:循環参照を防ぎ、メモリを明示的に解放する
Set taskMap = Nothing
End Sub
---
3. チーフアーキテクトからの忠告
① 循環参照の呪縛
動的マッピングで最も怖いのは、CSV内の論理的なミスによる「循環参照」だ。Projectは依存関係がループすると計算エンジンが停止する。上記コードでは `On Error Resume Next` で逃げているが、本来は依存関係を構築する前にグラフ理論における「トポロジカルソート」を適用し、閉路が存在しないことを保証すべきだ。
② メモリ管理の鉄則
VBAはガベージコレクションが極めて脆弱だ。`Set taskMap = Nothing` を忘れることは、大規模なプロジェクトファイルを開きっぱなしにするのと同義のメモリリークを招く。特に `Task` オブジェクトをループで回す際は、`Nothing` チェックを必ず行え。
③ キャッシュの同期
Projectのタスク名は一意とは限らない。もしプロジェクト内に同名のタスクが複数存在する場合、`Dictionary` のキーには「WBS番号」や「ユニークな識別子」を連結させた文字列を使用するのが、レガシーシステムを保守し続けるための保険となる。
—
結論
自動化とは、単にコードを書くことではない。データに潜む不整合をロジックでいかに無力化するかという、「戦い」である。
君たちがこれから扱うデータは、常に不完全だ。だが、この「名前からIDを逆引きする」という手法を身につければ、どんなに荒れたCSVファイルが送られてきても、それを一瞬でプロジェクトの構造へと昇華させることができる。
コードは淡々と、しかしメモリの隅々まで意識を張り巡らせて書け。それこそが、伝説となるための条件だ。
