Project VBAを掌中に収める:独自ロジックによる「真の進捗率」自動算出アーキテクチャ
MS Project標準の「%完了」に辟易したことはないか?
あれは単純な「時間軸の経過」に過ぎない。現場のPMが本当に知りたいのは、投入された「実績工数」に対する「残工数」の相対的な比率だ。標準フィールドに縛られ、泥臭い手作業でExcelに転記しているなら、今すぐその思考を停止せよ。
今日は、Projectのオブジェクトモデルを蹂躙し、メモリを極限まで最適化しながら、独自の進捗ロジックを強制実装する手法を授ける。
—
1. なぜ標準の進捗率では「現場」が死ぬのか
MS Projectの計算エンジンは、タスクの期間ベースで進捗を算出する。しかし、現実のプロジェクトでは「予定していた工数よりも、実際に費やした工数が上回る」ことは日常茶飯事だ。
我々が求めるのは以下の計算式である。
$$ \text{独自進捗率} = \frac{\text{実績工数}}{\text{実績工数} + \text{残工数}} \times 100 $$
この単純な算式を、Projectの`Task`オブジェクトから抽出し、カスタムフィールドへ秒単位で反映させる。これこそが、アーキテクトが為すべき自動化だ。
—
2. 実装の要諦:オブジェクトのライフサイクルとメモリ管理
VBAでProjectを扱う際、最も陥りやすい罠は「オブジェクトの放置」だ。特に数千行規模のスケジュールを回す際、`ActiveProject.Tasks`への安易なアクセスはメモリリークを招き、最悪の場合、計算がループしてハングアップする。
究極の計算ロジック実装
以下のコードは、単なる実装例ではない。`Object`の明示的解放と、計算後のキャッシュクリアを徹底した「現場で生き残る」ためのコードだ。
‘ Project VBAにおける進捗率算出の最適化実装
Public Sub CalculateCustomProgress()
Dim proj As Project
Dim tsk As Task
Dim actualWork As Double
Dim remainingWork As Double
‘ プロジェクトへの直接参照をキャッシュする(ループ内でのActiveProject呼び出しは厳禁)
Set proj = ActiveProject
‘ 画面更新を停止し、再描画のオーバーヘッドを殺す
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
For Each tsk In proj.Tasks
‘ 階層構造のサマリータスクは除外、または個別のロジックを適用する
If Not tsk Is Nothing Then
If Not tsk.Summary Then
‘ 工数は分単位で格納されるため、時間単位(h)に変換して計算
actualWork = tsk.ActualWork / 60
remainingWork = tsk.RemainingWork / 60
‘ ゼロ除算回避のガード節
If (actualWork + remainingWork) > 0 Then
‘ Text1カスタムフィールドに結果を格納(数値型ならNumber1へ)
tsk.Text1 = Format((actualWork / (actualWork + remainingWork)) 100, “0.00”) & “%”
Else
tsk.Text1 = “0.00%”
End If
End If
End If
Next tsk
CleanExit:
‘ オブジェクトの明示的解放(VBAのGCに期待してはならない)
Set tsk = Nothing
Set proj = Nothing
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
Debug.Print “Error: ” & Err.Number & ” – ” & Err.Description
Resume CleanExit
End Sub
—
3. シニアエンジニアのための極限の知見
A. Windows APIによる非同期監視
もし、この計算を「更新時」にリアルタイムで走らせたいのであれば、`Project_Change`イベントに頼るな。あれは重すぎる。代わりに、Windows APIの`SetTimer`を使用し、計算処理を別スレッド的な挙動(実際にはメインループの合間)で行う設計を検討せよ。これにより、ユーザーの入力を阻害しない「ノンブロッキングな進捗計算」が可能となる。
B. レガシー連携:CSV/XMLエクスポートの罠
このツールで計算した結果を上層部のBIツールに渡す際、クリップボード経由や手動のコピペは情弱の極みだ。`Project.Export`メソッドを駆使し、スキーマ定義ファイルを介してXML化し、REST API経由で上位システムへプッシュするパイプラインを構築せよ。
C. パフォーマンスチューニングの極意
数万タスクを超える巨大なプロジェクトの場合、`For Each`は遅い。`TaskID`をインデックスとして直接配列にロードし、メモリ上で計算を完結させてから、一括で`Task.SetField`を行う手法を推奨する。これは、VBAにおける「バルク更新」の鉄則だ。
—
結びに代えて
自動化とは、単にコードを書くことではない。システムという生命体の「血流(データ)」をいかに最適化し、PMの意思決定を淀みなくサポートするか、その一点に集約される。
標準機能が足りないなら、自らの手で実装すればいい。それが、伝説的なアーキテクトに求められる唯一の資格だ。
健闘を祈る。貴殿のプロジェクトが、真の数値に裏打ちされた合理的な航海となることを。
