Project VBAの深淵:カレンダー駆動型スケジューリングの極致
諸君。VBAという古の言語を単なる「マクロ記録の延長」と侮っているなら、今すぐその認識を改めるべきだ。特にProject VBA(Microsoft Project Object Library)を用いたWBSの自動構築は、単なる階層の操作ではない。それは「時間」という四次元の制約を、メモリ空間上のオブジェクトグラフとして再構築する重厚なエンジニアリングだ。
今回は、多くの者が躓く「カレンダーの非同期性」を攻略し、タスクの稼働日計算をプロフェッショナルな領域へと昇華させる知見を共有する。
—
1. カレンダーの階層構造を掌握せよ
Projectには「プロジェクト標準カレンダー」と「タスク固有カレンダー」が存在する。未熟な実装者は、`Project.Calendar`のみを参照してタスク開始日を計算しようとするが、これこそがバグの温床だ。
タスクオブジェクトには `Calendar` プロパティが直結している。もしタスクが「標準カレンダー」を継承していない場合、計算結果は常にズレる。
極限の知見:
稼働日計算を行う際は、必ず `Task.Calendar` オブジェクトを走査せよ。存在しない場合は `Project.BaseCalendars` をフォールバックとして参照する、という階層的解決ロジックを実装するのがシニアの流儀だ。
—
2. VBAによる稼働日計算の実装(メモリ最適化を添えて)
`Task.Work` や `Task.Start` を計算する際、ループ内でむやみにオブジェクトを取得し続けると、VBAのガベージコレクション(GC)は悲鳴を上げる。以下のコードは、メモリリークを最小限に抑えつつ、カレンダーベースの計算を行うためのテンプレートだ。
‘ プロジェクト標準とタスクカレンダーを考慮した稼働日算出
Public Function GetWorkDate(ByRef tsk As Task, ByVal startDate As Date, ByVal durationDays As Long) As Date
Dim pj As Project
Dim cal As Calendar
Dim i As Long, count As Long
Dim currentDt As Date
Set pj = tsk.Project
‘ タスク固有カレンダーが未設定ならプロジェクト標準を参照
If tsk.Calendar Is Nothing Then
Set cal = pj.BaseCalendars(pj.DefaultTable)
Else
Set cal = tsk.Calendar
End If
currentDt = startDate
Do While count < durationDays
' Calendar.Period.Working で該当日の稼働状況を判定
If cal.Period(currentDt).Working Then
count = count + 1
End If
If count < durationDays Then currentDt = DateAdd("d", 1, currentDt)
Loop
GetWorkDate = currentDt
' 明示的なオブジェクト解放(循環参照の防止)
Set cal = Nothing
Set pj = Nothing
End Function
---
3. Windows APIによるパフォーマンスチューニング
数千タスクを抱える大規模WBSの再計算において、VBAの逐次処理はボトルネックとなる。`Application.ScreenUpdating = False` は基本だが、さらに踏み込んで `DoEvents` の投下回数を制御 すること。
また、WBSの依存関係(Predecessors)を書き換える際は、`Task.LinkPredecessors` メソッドを多用せず、`Application.CalculateAll` をループの外で一回だけ呼ぶ設計にしろ。内部エンジンへの命令回数を減らすことこそが、VBAパフォーマンスの真髄だ。
—
4. レガシー環境とアーキテクチャの生存戦略
Windows APIを用いた「カレンダーの例外日付(祝日・長期休暇)」の外部取得も重要だ。API経由でExcelの祝日マスタを読み込み、Projectの `Calendar.Exceptions` をプログラムで動的に更新する仕組みを作れば、保守担当者がカレンダーを手動でカチカチと設定する地獄のような工数から解放される。
シニアの警告:
`Exceptions.Add` を実行する際は、必ず `Type:=pjExceptionTypeWorking` を意識せよ。デフォルトは非稼働設定になることが多いため、休日出勤対応のロジックが破綻するケースが後を絶たない。
—
結論
Project VBAを操るということは、単にタスクを並べることではない。ビジネスの「時間軸」を計算可能なデータモデルへと変換することだ。
- メモリを食うな:オブジェクトの明示的解放を徹底せよ。
- 計算を最適化せよ:再計算エンジン(Calculate)の叩くタイミングを制御せよ。
- カレンダーを信じるな:必ずタスク固有のコンテキストを確認せよ。
この知見を実装に落とし込めば、君たちの構築するProjectシステムは、どんな複雑なWBSであっても「正確な未来」を予測する力を持つはずだ。健闘を祈る。
