【Project VBA】ALAP制約による「納期逆算型」スケジュールエンジンの深淵
VBAを単なる「事務作業の自動化ツール」と見なすのは、アーキテクトとしては三流だ。Project VBA、特にMS Projectのオブジェクトモデルを掌握するということは、メモリ空間の端から端まで、スケジュールの制約という名の「論理的鎖」を制御することに他ならない。
今回は、納期(Deadline)を起点に全タスクを配置するALAP(As Late As Possible:可能な限り遅く)制約を用いたスケジュールエンジンの核心に迫る。
—
1. なぜ「ALAP」は鬼門なのか
多くの初学者は、`Task.Start`に直接値を代入してスケジュールを組もうとする。これは大いなる過ちだ。MS Projectの計算エンジンは、一度手動で値を書き込むと「制約の固定(Constraint Type)」が自動的に発生し、後続の依存関係による動的な再計算を阻害する。
ALAP制約の真髄は、「終了日を固定し、依存関係(Predecessors)を逆流させて開始日を自動算出させる」ことにある。これをVBAで制御するには、`pjConstraintALAP`をプロパティとして適用するだけでなく、プロジェクトの計算モードと同期させなければならない。
—
2. 実装の設計思想:メモリ管理と安全なAPI呼び出し
VBAで大規模なスケジュールを扱う際、最も避けなければならないのは、MS Projectのオブジェクトモデルが生成する「一時的な参照の残留」によるメモリリークだ。`Set obj = Nothing`を繰り返すだけでは不十分。COMオブジェクトのライフサイクルを意識せよ。
ALAPスケジュール生成エンジン(コアロジック)
‘ プロジェクトのタスクに対してALAP制約を適用し、納期を起点に逆算する
Public Sub ApplyALAPConstraint(ByRef proj As Project, ByVal targetTaskID As Long, ByVal deadLineDate As Date)
Dim tsk As Task
Set tsk = proj.Tasks(targetTaskID)
‘ 1. 制約をALAPに設定(これにより自動的に期間計算が逆算モードに入る)
tsk.ConstraintType = pjConstraintALAP
‘ 2. 納期を締め切りとして設定(Deadlineプロパティは計算を固定しないため重要)
tsk.Deadline = deadLineDate
‘ 3. パフォーマンス最適化:再計算のトリガーを抑制
‘ 大量タスク更新時は Calculation プロパティを一旦手動に切り替えるのが鉄則
Dim originalCalcMode As PjCalculation
originalCalcMode = Application.Calculation
Application.Calculation = pjManual
‘ — ここで依存関係のチェックや調整を行う —
‘ 4. 再計算を強制実行し、ALAPの論理を反映させる
Application.Calculation = originalCalcMode
Application.CalculateProject
‘ メモリの明示的解放(オブジェクトの参照カウントを意識)
Set tsk = Nothing
End Sub
—
3. レガシー環境を生き抜くための極限の知見
Windows APIによるタスクの同期
MS Projectの計算エンジンはバックグラウンドで非同期に動くことがある。特に大量のタスクを更新する際、`Application.CalculateProject`が完了する前に次の処理へ移ると、計算結果が不整合を起こす。
これを防ぐには、Windows API `Sleep` を利用し、計算完了まで待機するポーリング処理を実装するのが、現場のエンジニアが辿り着く「泥臭いが確実な」解法だ。
If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If
‘ 計算完了まで待機するセーフティネット
Public Sub WaitUntilCalculated(ByVal app As MSProject.Application)
Do While app.IsCalculating
Sleep 100 ‘ 100msの待機でCPU負荷を抑えつつ待機
DoEvents
Loop
End Sub
—
4. チーフアーキテクトからの忠告:保守性を殺すな
このツールを組織に導入する際、最も注意すべきは「MS ProjectのGUI上でユーザーが値を弄る」リスクだ。VBAで制御したロジックを、ユーザーが手動入力で破壊する事態を防ぐには、以下の実装を推奨する。
- カスタムフィールドの活用: ALAP制御対象のタスクには、`Flag1`などのカスタムフィールドに`True`を立て、手動変更を検知するイベントプロシージャ(`Project_BeforeTaskChange`)を実装せよ。
- 整合性チェックの自動化: ロジック実行後、必ず`Task.ConstraintDate`と`Task.Start`の差分を検証するログを出力させること。
結びに代えて
VBAでスケジュールエンジンを組むということは、単なるコード記述ではない。MS Projectという巨大なCOMサーバーの内部ロジックを、あなたのコードで「調教」する行為だ。
ALAP制約は、納期という「絶対的な終端」から逆算する。これこそが、不確実なプロジェクトを制御下に置くための、もっとも静かで、もっとも強力な武器となる。
コードに魂を込めよ。その一行が、明日から現場の誰かの「残業」を救うかもしれないのだから。
