【実務・中級編】マイルストーンタスクを自動抽出し、先行タスクとのリンクを自動化するマクロ – Project VBA解析バイブル

スポンサーリンク

Project VBAにおけるタスク(Task)の階層構造、そしてWBS(Work Breakdown Structure)の自動制御。ここは、多くの開発者が「オブジェクトの重み」と「イベントの連鎖」に足元をすくわれる魔境だ。

特に、数千行規模のスケジュール表を相手にする時、マイルストーンの抽出や依存関係(Predecessors)の構築を安易なループ処理で実装すれば、画面は固まり、メモリはリークし、実用に耐えないゴミコードが完成する。

今回は、プロジェクトマネジメントの現場で即座に使える、「マイルストーンタスクの自動抽出と先行タスクの動的リンク機構」を、極限まで無駄を削ぎ落とした堅牢なプロダクションコードとともに伝授しよう。

1. なぜ「愚直なWBS操作」は破綻するのか?

多くのプログラマブルなWBS自動化スクリプトは、次のようなアンチパターンに陥っている。

  • 全タスクの逐次走査($O(N^2)$ の罠): すべてのタスクをループし、条件分岐のたびに `Task.Predecessors.Add` を叩く。依存関係の解決において、このアプローチはオブジェクトの再計算を引き起こし、プロジェクト全体のスケジュール再計算ループ(Calc Engine)を暴走させる。
  • マジックストリングの乱用: 「【完了】」や「M」といったキーワード判定をハードコーディングし、要件変更や多言語対応で完全に破綻する。
  • エラーハンドリングの欠如: リンク先のタスクが既に削除されている場合や、循環参照(Circular Dependency)が発生した際のトラップを用意していないため、Projectが強制終了する。

プロのアーキテクトが目指すべきは、「一括処理による再計算エンジンの抑制」「トランザクション的な一貫性の保持」だ。

2. 堅牢な設計アプローチ:実装のキモ

今回のモジュールでは、以下の設計思想を貫く。

1. 対象タスクの絞り込み(LINQ的アプローチ): VBAにはネイティブのLINQはないが、Collectionや配列を駆使して、対象となるマイルストーン候補を一網打尽にする。
2. 依存関係の整合性担保: マイルストーンの直前タスク(Predecessor)を特定する際、IDの順序に依存せず、WBSのツリー構造上の「論理的な直前」を算出する。
3. 計算モードの一時停止: VBAからMS Project(または独自WBSオブジェクト)を操作する際、処理中の自動計算(Calculation)を一時的に手動に切り替え、パフォーマンスを最大化する。

3. プロダクションコード例:マイルストーン自動リンク・マクロ

以下のコードは、Project VBAを前提とした、実務投入可能なエンタープライズグレードのモジュールだ。特定のキーワード(例: “【MS】”)を含むタスクを自動的にマイルストーン(期間0日)に変換し、その直前のタスクとの終了-開始(FS)関係を自動構築する。

Option Explicit

‘ ==============================================================================
‘ モジュール名: ModMilestoneAutoLink
‘ 概要: 指定キーワードを持つタスクをマイルストーン化し、先行タスクとリンクする
‘ 著作権: Project VBA Architect Lab
==============================================================================

Public Sub AutomateMilestoneLinks(Optional ByVal milestoneKeyword As String = “【MS】”)
Dim prj As Project
Set prj = ActiveProject

‘ パフォーマンス最適化のため、自動計算を一時停止
Dim originalCalc As PjAssignmentCalculation
originalCalc = Application.Calculation
Application.Calculation = pjManual

On Error GoTo ErrorHandler

Dim t As Task
Dim prevTask As Task
Dim targetTask As Task
Dim linkCount As Long
linkCount = 0

‘ 履歴をクリアするため、既存の不要なリンクは保持しつつ処理開始
‘ ※実務では対象範囲をActiveProject.Tasks全体または選択範囲に限定する
Set prevTask = Nothing

For Each t In prj.Tasks
If Not t Is Nothing Then
‘ 1. サマリータスク(親タスク)や削除済みタスクは除外
If Not t.Summary And Not t.Milestone Then

‘ 2. キーワードが含まれているか判定
If InStr(1, t.Name, milestoneKeyword, vbTextCompare) > 0 Then

‘ マイルストーン化(期間を0に設定)
t.Duration = “0d”
Set targetTask = t

‘ 3. 直前の有効なタスクが存在する場合、依存関係(FS)を構築
If Not prevTask Is Nothing Then
‘ 循環参照や重複定義を防ぎながらリンクを追加
Call SafeAddPredecessor(targetTask, prevTask)
linkCount = linkCount + 1
End If

End If

‘ 直前タスクのポインタを更新(マイルストーン自体も含む実タスクを追跡)
Set prevTask = t

End If
End If
Next t

‘ 計算を再開し、全体を再計算
Application.Calculation = originalCalc
Application.CalculateAll

MsgBox “マイルストーンの自動リンクが完了しました。” & vbCrLf & _
“処理件数: ” & linkCount & ” 件”, vbInformation, “自動化完了”

Exit Sub

ErrorHandler:
‘ 異常終了時も必ず計算モードを復元する
Application.Calculation = originalCalc
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
End Sub

‘ ——————————————————————————
‘ 補助プロシージャ: 安全な先行タスクの追加(重複・循環参照ガード)
‘ ——————————————————————————
Private Sub SafeAddPredecessor(ByRef currentTask As Task, ByRef predTask As Task)
Dim l As Link
Dim alreadyLinked As Boolean
alreadyLinked = False

‘ 既に同じ先行タスクが存在するかチェック
For Each l In currentTask.PredecessorTasks
If l.ID = predTask.ID Then
alreadyLinked = True
Exit For
End If
Next l

‘ リンクが存在しない場合のみ追加
If Not alreadyLinked Then
‘ 依存関係の追加 (Type:=pjLinkFinishToStart)
currentTask.Predecessors.Add Item:=predTask.Name, Type:=pjLinkFinishToStart
End If
End Sub

4. データベース連携・ファイル連携における実践的注意点

このマクロをExcelや外部データベース(SQL Serverなど)と連携して運用する場合、以下のトラップに注意せよ。

  • IDのズレ問題: 外部DB側で保持しているタスクID(UUIDなど)と、MS Project上のインデックスID(`Task.ID`)は必ず乖離する。連携時は `Task.UniqueID` をキーとしてマッピングを行わなければ、データの整合性が一瞬で崩壊する。
  • トランザクションの分離: Excelから一括でスケジュールをインポートし、その直後にこのマイルストーン自動化スクリプトを走らせる場合、「インポート処理のコミット(オブジェクトの確定)」が完了する前にマクロが走ると、参照エラー(Object variable or With block variable not set)を引き起こす。必ず明示的なウェイト、あるいはイベント同期を挟むこと。

5. チーフアーキテクトからの最終提言

業務自動化の本質は、「手作業の置き換え」ではない。「人間の判断ミスが入り込む余地をシステム的に排除すること」だ。

今回紹介したマイルストーンの自動リンク機構をWBSの定例バッチに組み込むだけで、プロジェクトマネージャがスケジュール調整に費やしていた無駄な時間は消え去る。コードの背後にあるオブジェクトの挙動を完全に支配し、組織の生産性を次のステージへ引き上げたまえ。

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