依存関係の「複雑度」をスコアリング:リンクが多すぎるタスクを自動抽出する品質管理
プロジェクトマネジメントにおいて、WBS(Work Breakdown Structure)のタスク間依存関係(先行・後続タスク)の網は、プロジェクトの生命線だ。しかし、現場の担当者に任せきりにされたスケジュールは、往々にして「モンスター・タスク」を生み出す。
特定のタスクに何本ものリンクが集中し、誰も全体像を把握できない「スパゲッティ状態のWBS」。これが引き起こすのは、変更に対する致命的なドミノ倒しと、プロジェクトの完全な硬直化である。
今回は、Project VBAのオブジェクトモデルの深部を突くアプローチで、「タスクの依存関係の複雑度を自動スコアリングし、破綻寸前のボトルネックを炙り出す品質管理エンジン」の全貌を伝授する。
—
なぜ「スパゲッティWBS」は見逃されるのか?
標準的なMS Projectの画面では、ガントチャートの矢印や「先行タスク(Predecessors)」「後続タスク(Successors)」のID文字列がカンマ区切りで並ぶだけだ。これらを人間が目視で確認し、「このタスクはリンクが多すぎてメンテナンス不能だ」と判定するのは不可能に近い。
ここで発生する実務上のリスクは以下の通りだ。
1. 変更伝播の暴走: 1つのタスクが遅延した際、後続の数十個のタスクへ無秩序に影響が波及する。
2. クリティカルパスの隠蔽: 複雑すぎる依存関係の裏に、真のボトルネックが埋没する。
3. 担当者の孤立: どのタスクと連動しているか分からないため、担当者がスケジュールを更新できなくなる。
これを防ぐには、「次数(Degree:出次数・入次数)」の概念を導入し、タスクの複雑度を数値化して客観的にフィルタリングする仕組みが不可欠となる。
—
堅牢な設計思想:プロジェクトオブジェクトのライフサイクルとパフォーマンス
VBAでMS Projectを操作する際、最大の罠は「不必要な画面描画とオブジェクトアクセスのオーバーヘッド」だ。数千行に及ぶWBSに対して、ループ内でいちいちタスクの依存関係コレクション(`TaskPredecessors` / `TaskSuccessors`)を叩くと、処理が数分単位でフリーズする。
プロフェッショナルな設計として、以下の鉄則を遵守する。
- 画面描画の完全な抑制: `ScreenUpdating False` により、COMコンポーネントとの無駄な往復を断つ。
- コレクションの遅延評価とキャッシュ: 依存関係のカウントは一度取得したらメモリ上に保持し、二重アクセスを避ける。
- カスタムフィールド(Text / Number)の有効活用: スコアリング結果を目視可能なように、タスクの拡張フィールドに書き戻してフィルタリングを容易にする。
—
プロダクションコード:依存関係複雑度スコアリングエンジン
以下のコードは、Project VBAの標準モジュールにそのまま貼り付けて実行できる。アクティブなプロジェクトの全タスクを走査し、先行・後続の総数(Total Degree)および、その比率から「複雑度スコア」を算出して、数値フィールド(例: `Number1`)に格納し、一定値を超えたタスクをログ出力する。
‘ ==============================================================================
‘ Module: ModTaskComplexityAnalyzer
‘ Description: タスクの依存関係の次数(Degree)を解析し、複雑度をスコアリングする
‘ Author: Enterprise Project Automation Architect
‘ ==============================================================================
Option Explicit
Public Sub AnalyzeTaskComplexity()
Dim prj As Project
Set prj = ActiveProject
‘ ————————————————————————–
‘ 1. パフォーマンス最適化の鉄則:描画とイベントの抑制
‘ ————————————————————————–
App.ScreenUpdating = False
On Error GoTo ErrorHandler
Dim tsk As Task
Dim predCount As Long
Dim succCount As Long
Dim complexityScore As Double
Dim highRiskCount As Long
highRiskCount = 0
‘ 閾値設定(この数を超えるリンクを持つタスクは「要警戒」とする)
Const COMPLEXITY_THRESHOLD As Double = 5.0
Debug.Print “=== タスク依存関係 複雑度分析開始 ===”
‘ ————————————————————————–
‘ 2. 全タスクの走査とスコアリング
‘ ————————————————————————–
For Each tsk in prj.Tasks
‘ サマリタスク(親タスク)やマイルストーンを除外する場合はここでガードを入れる
If Not tsk Is Nothing Then
If Not tsk.Summary Then
‘ 先行タスク数(入次数: In-Degree)と後続タスク数(出次数: Out-Degree)を取得
‘ ※エラーハンドリング:リンクが存在しない場合はエラーになるためCountプロパティを安全に評価
predCount = GetSafePredecessorCount(tsk)
succCount = GetSafeSuccessorCount(tsk)
‘ 【スコアリングロジック】
‘ 単純な合計だけでなく、双方向の交錯度(バランス)も考慮した独自の複雑度計算
‘ 例: 先行と後続の積、あるいは単純な総数
complexityScore = CDbl(predCount + succCount)
‘ 結果をカスタム数値フィールド(Number1)に書き込み(ビューでの視覚化用)
‘ ※MS ProjectのNumber1~20は自由にカスタム可能
tsk.Number1 = complexityScore
‘ 複雑度が閾値を超えている場合の処理
If complexityScore >= COMPLEXITY_THRESHOLD Then
highRiskCount = highRiskCount + 1
Debug.Print “【高リスク検知】 ID: ” & tsk.ID & ” | 名称: ” & tsk.Name & _
” | 先行: ” & predCount & ” | 後続: ” & succCount & _
” | 複雑度スコア: ” & complexityScore
‘ 該当タスクの色を赤色に変えて視覚的に警告(視覚的フィードバック)
‘ tsk.FontColor = pjRed ‘ 必要に応じて有効化
Else
tsk.Number1 = complexityScore
End If
End If
End If
Next tsk
Debug.Print “=== 分析完了. 高リスクタスク検出数: ” & highRiskCount & ” ===”
MsgBox “タスクの複雑度分析が完了しました。” & vbCrLf & _
“検出された高リスク(複雑度 >= ” & COMPLEXITY_THRESHOLD & “)タスク数: ” & highRiskCount & vbCrLf & _
“※ 結果は [Number1] フィールドに書き込まれました。”, vbInformation, “品質管理システム”
CleanUp:
App.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume CleanUp
End Sub
‘ ——————————————————————————
‘ Private Helper: 先行タスク数を安全に取得する
‘ ——————————————————————————
Private Function GetSafePredecessorCount(ByVal tsk As Task) As Long
On Error GoTo ErrHandler
Dim cnt As Long
cnt = tsk.TaskPredecessors.Count
GetSafePredecessorCount = cnt
Exit Function
ErrHandler:
GetSafePredecessorCount = 0
End Function
‘ ——————————————————————————
‘ Private Helper: 後続タスク数を安全に取得する
‘ ——————————————————————————
Private Function GetSafeSuccessorCount(ByVal tsk As Task) As Long
On Error GoTo ErrHandler
Dim cnt As Long
cnt = tsk.TaskSuccessors.Count
GetSafeSuccessorCount = cnt
Exit Function
ErrHandler:
GetSafeSuccessorCount = 0
End Function
—
現場で即座に活かすための運用プラクティス
このスクリプトを単に動かして終わりにしてはならない。真の業務自動化エンジニアであれば、これを「プロジェクトの定例品質ゲート」に組み込む。
1. カスタムビューの作成:
MS Project側で、`Number1` フィールドを表示した「複雑度分析ビュー」をあらかじめ定義しておく。スクリプト実行後、このフィールドで降順ソートすれば、プロジェクト全体の「魔境」が一発で特定できる。
2. 自動レポート生成への拡張:
上記の `Debug.Print` やメッセージボックスだけでなく、結果をExcelへエクスポートし、Power BIなどのダッシュボードと連携させることで、PMO(プロジェクトマネジメントオフィス)全体でリスクを定量監視できるようになる。
3. 定期実行(タイマー連携)の回避:
タスクの依存関係は頻繁に変わるものではないため、プロジェクトのベースライン設定時や、週次定例の直前バッチとして手動(またはリボンカスタマイズによるボタン1つ)で実行させる設計が最も堅牢である。
アーキテクトからの提言
「スケジュールが遅れている」という現象の根底には、大抵の場合、こうした構造的な複雑化(Technical Debt)が潜んでいる。人間は目に見えないものを管理できない。
コードによって見えない依存関係を「数値」という光に照らし出すこと。それこそが、ツールを作る我々エンジニアが現場にもたらすべき最大のバリューである。スパゲッティWBSを駆逐し、真にコントロール可能なプロジェクトを手に入れてほしい。
