泥臭い「ID依存」を捨てろ。Project VBAでタスク名をキーにする「動的依存関係構築」の極意
VBAでMicrosoft Projectを制御する際、多くのエンジニアが陥る罠がある。それは、インポート元のCSVとプロジェクトファイルの「ID」を同期させようとすることだ。
「IDは挿入や削除で簡単にズレる」。実務でこれを知らない者は、自動化ツールを組んだ翌日に崩壊したスケジュールを泣きながら修正する羽目になる。
真のプロフェッショナルは、「不変なもの(名前)」をキーに「流動的なもの(ID)」を特定するという設計思想を持つ。今回は、CSVから読み込んだタスク名を探索し、動的に先行タスク(Predecessors)をリンクさせる、堅牢で保守性の高いロジックを伝授しよう。
—
1. なぜ「ID」をキーにしてはいけないのか
プロジェクト管理において、タスクIDは単なる「現在の行番号」に過ぎない。行の入れ替えやソートが発生すれば、IDは一瞬で無意味になる。
一方で「タスク名」は、プロジェクトが続く限り一意であるべき(あるいは一意に管理すべき)ID的な存在だ。我々が書くべきは、「名前でタスクオブジェクトを特定し、そのIDを抽出してリンクを張る」という、抽象度の高いマッピングロジックである。
—
2. 堅牢なインポートロジックの設計方針
この自動化ツールには、以下の3つの鉄則を課す。
1. Dictionaryオブジェクトによる探索コストの削減: 全タスクを毎回ループで回すのは愚策だ。初回に名前とIDをDictionaryにキャッシュし、O(1)で検索せよ。
2. エラーハンドリングの徹底: 「先行タスクが見つからない」場合、プログラムを止めずにログを吐き出し、プロセスを完走させる。
3. リンクの重複防止: 既にリンクが存在する場合の重複排除を考慮する。
—
3. 実践コード:名前ベースの動的依存関係構築
以下は、CSV(タスク名, 先行タスク名)を読み込み、Project上のタスクへリンクを反映させるプロシージャだ。
‘ 必要な参照設定: Microsoft Project 16.0 Object Library
‘ Microsoft Scripting Runtime (Dictionary用)
Public Sub ImportDependenciesFromCSV(csvPath As String)
Dim proj As Project: Set proj = ActiveProject
Dim dictTasks As Object: Set dictTasks = CreateObject(“Scripting.Dictionary”)
‘ 1. 名前とIDのキャッシュ(高速化の要)
Dim t As Task
For Each t In proj.Tasks
If Not t Is Nothing Then
If Not dictTasks.Exists(t.Name) Then
dictTasks.Add t.Name, t.ID
End If
End If
Next t
‘ 2. CSV読み込みとリンク構築
Dim fileNum As Integer: fileNum = FreeFile
Dim lineData As String, parts() As String
Open csvPath For Input As #fileNum
Line Input #fileNum, lineData ‘ ヘッダー読み飛ばし
Do Until EOF(fileNum)
Line Input #fileNum, lineData
parts = Split(lineData, “,”)
Dim taskName As String: taskName = parts(0)
Dim predName As String: predName = parts(1)
‘ 3. 動的マッピング
If dictTasks.Exists(taskName) And dictTasks.Exists(predName) Then
Dim targetTask As Task: Set targetTask = proj.Tasks(dictTasks(taskName))
Dim predID As Long: predID = dictTasks(predName)
‘ リンク設定(既にリンクがある場合はスキップ等のロジックをここに)
targetTask.TaskDependencies.Add proj.Tasks(predID)
Else
Debug.Print “警告: タスクが見つかりません -> ” & taskName & ” / ” & predName
End If
Loop
Close #fileNum
MsgBox “依存関係の構築が完了しました。”
End Sub
—
4. プロダクション環境への導入アドバイス
このコードを実務で運用する際、以下の点に注意せよ。
- タスク名の正規化: CSVとProject上のタスク名で、全角・半角の揺れや、末尾のスペースが残ることがある。`Trim(StrConv(name, vbNarrow))` 等で読み込み時に正規化する関数を挟むのが定石だ。
- トランザクションの意識: 大量データを扱う場合、`Application.ScreenUpdating = False` を活用せよ。Projectの再計算ロジックが走るたびに描画を更新すると、処理時間が指数関数的に増大する。
- 循環参照の回避: 依存関係を自動構築すると、ループ状のリンク(A→B→A)が生まれる可能性がある。Projectの標準機能で警告が出るが、ツール側でも事前にトポロジカルソートのチェックを入れるのが、アーキテクトとしての矜持だ。
最後に:VBAを「自動化の呪い」にしないために
「動けばいい」コードは、半年後の自分を殺す。今回紹介したDictionaryによるキー検索は、データ量が増えてもパフォーマンスが劣化しない、非常にスケーラブルな手法だ。
IDに依存せず、論理的な名前で紐解く。このアプローチこそが、複雑なプロジェクトを制御するための唯一の解である。さあ、このコードを武器に、手作業による地獄のスケジュール修正から自らを解放してくれ。
