Project VBAの深淵:マイルストーンを「絶対的基準点」へと昇華させる制約制御術
Projectのスケジュール管理において、我々アーキテクトが最も恐れるのは「計算エンジンの暴走」だ。ASAP(可能な限り早く)やALAP(可能な限り遅く)といった動的制約は、一見便利だが、複雑な依存関係の中では連鎖的な再計算を引き起こし、意図せぬ工期圧縮や延長を招く。
特にマイルストーンはプロジェクトの要石だ。これを計算エンジンの気まぐれに委ねることは、設計図の基準点を固定せずに建物を建てるに等しい。今回は、Project VBAのオブジェクトモデルを掌握し、マイルストーンに「終了日固定(Finish No Earlier Than / Must Finish On)」を強制付与する、堅牢なスクリプトを提示する。
1. 計算エンジンの挙動を制御する「制約」の解剖
Projectのオブジェクトモデルにおいて、`Task`オブジェクトの`ConstraintType`プロパティは、スケジューリングの挙動を決定づける門番である。マイルストーンを固定する場合、`pjMFOn`(Must Finish On)または`pjFNET`(Finish No Earlier Than)を明示的に指定する必要がある。
ここで注意すべきは、単に値を代入するだけでは計算エンジンが「待機状態」に入り、リソース平準化やリンクの影響で値が上書きされるリスクがあることだ。「確定した日付」を「確定した制約」として書き込むには、正しい順序でプロパティを叩く必要がある。
2. 極限の最適化を施したVBAコード
以下のコードは、単なるプロパティ設定に留まらない。メモリリークを許さないオブジェクト解放、および大規模プロジェクトでの実行を想定したエラーハンドリングを実装している。
‘ —————————————————————————–
‘ @Description: マイルストーンタスクに対し「終了日固定」制約を強制付与する
‘ @Author: Chief Architect
‘ @Note: メモリ解放とオブジェクトの正当性を担保するプロダクションコード
‘ —————————————————————————–
Public Sub SetMilestoneFixedConstraint()
Dim prjApp As Object
Dim tsk As Object
Dim tskSelection As Object
‘ Late Bindingによる動的参照(参照設定の手間を省き、環境依存を排除)
Set prjApp = Application
On Error GoTo ErrorHandler
‘ 計算エンジンの負荷を考慮し、選択範囲に対してのみ実行(大規模プロジェクト対策)
Set tskSelection = prjApp.ActiveSelection.Tasks
If tskSelection Is Nothing Then Exit Sub
‘ トランザクション処理の開始(Undoの起点)
prjApp.UndoContext.Begin (“Set Milestone Fixed Constraint”)
For Each tsk In tskSelection
‘ マイルストーン判定(Durationが0であることは絶対条件)
If tsk.Milestone Then
‘ 終了日固定制約(Must Finish On)を付与
‘ 既に設定されている場合は上書きし、計算エンジンに強制反映させる
tsk.ConstraintType = pjMFOn
tsk.ConstraintDate = tsk.Finish
‘ ログ出力(デバッグウィンドウ用)
Debug.Print “Fixed: ” & tsk.Name & ” at ” & tsk.Finish
End If
Next tsk
CleanExit:
‘ 明示的なオブジェクト解放
Set tsk = Nothing
Set tskSelection = Nothing
Set prjApp = Nothing
prjApp.UndoContext.End
Exit Sub
ErrorHandler:
MsgBox “Critical Error: ” & Err.Description, vbCritical
Resume CleanExit
End Sub
3. 実践的知見:シニアエンジニアが押さえるべき落とし穴
オブジェクトの明示的解放(メモリ管理)
VBAはガベージコレクションが脆弱だ。`For Each`ループ内で`Task`オブジェクトをループさせる際、変数を解放せずに終了すると、ProjectのCOMインターフェースがゾンビプロセス化することがある。`Set tsk = Nothing`をループ外の`CleanExit`に配置するのは定石中の定石だ。
計算エンジンとの競合回避
もし大規模なスケジュール(数千タスク)を扱う場合、`Application.Calculation = pjManual` を一時的に設定し、全制約付与後に再計算させることで、パフォーマンスを劇的に向上させることが可能だ。しかし、これにはプロジェクトの整合性を維持するための高度な検証ロジックが別途必要となる。
外部連携(API接続)
もしこのツールを外部の進捗管理システムと連携させる場合、`tsk.ConstraintDate`を設定した後に必ず `tsk.UpdateProject` を呼び出し、サーバー側の計算エンジンと整合性を取ることを推奨する。クライアント側のキャッシュとサーバーの計算結果に齟齬が生じるのは、分散システムにおける「負けパターン」の筆頭だからだ。
最後に:制御こそがアーキテクチャの核心
マイルストーンを固定するということは、プロジェクトの「揺らぎ」をあえて排除する意志表明だ。エンジニアリングとは、混沌とした現実を、管理可能なモデルへと昇華させるプロセスに他ならない。
このスクリプトが、貴殿の管理するプロジェクトの安定性に寄与することを願う。コードは道具であり、意志を宿らせるのは使い手である貴殿自身だ。さらなる高度なカスタマイズが必要な際は、またこの場所で対峙しよう。
