Project VBAの深淵:プロジェクト開始日シフトに伴う「整合性崩壊」をコードで制圧する
プロジェクトマネジメントにおいて、スケジュール変更は日常茶飯事だ。しかし、Project VBAを用いてWBSを制御する際、最も恐ろしいのは「開始日を1日ずらした瞬間に、依存関係の論理が崩壊し、タスクが過去に遡る」という事態だ。
多くの初学者は、各タスクを個別にループで回し、`Task.Start`を書き換えるという愚を犯す。これでは、制約条件(Constraint)やリンク(Predecessor)が複雑に絡み合った巨大なWBSにおいて、計算の矛盾が連鎖し、整合性が取れなくなる。
今日は、Project VBAのアーキテクチャを理解した者が実装すべき、「堅牢な一括再計算ロジック」を伝授する。
—
1. なぜ「力技の更新」が失敗するのか
Projectのスケジュールエンジンは、タスクを単なる日付の箱として扱っていない。「制約条件の種類(Start No Earlier Than等)」や「カレンダー設定」を考慮した計算モデルを内部で保持している。
VBAで直接日付を代入することは、このエンジンに無理やり割り込む行為だ。「依存関係を無視した日付の直接代入」は、WBSの整合性を破壊する最も手軽な方法であることを理解してほしい。
鉄則:エンジンの挙動を制御せよ
日付を動かす際は、以下の手順を厳守する。
1. 依存関係の断絶を回避する: リンクされているタスクは、先頭のタスクを動かせば後続は自動追従する。
2. 制約条件の確認: `ConstraintType`が「指定日以降に開始」になっている場合、日付を強制変更すると制約違反が発生する。
3. 計算の再トリガー: `Project.Calculate` を呼び出し、内部エンジンに整合性を再計算させる。
—
2. 実装:プロジェクト開始日一括シフト・スクリプト
このコードは、プロジェクト全体の開始日を基準に、全タスクのオフセットを計算するプロダクションコードだ。
Option Explicit
‘ プロジェクト全体の日程を安全にシフトさせるエンジン
Public Sub ShiftProjectStart(newStartDate As Date)
Dim proj As Project
Set proj = ActiveProject
Dim tsk As Task
Dim offsetDays As Long
‘ プロジェクト開始日の差分を算出
offsetDays = DateDiff(“d”, proj.ProjectStart, newStartDate)
If offsetDays = 0 Then Exit Sub
‘ 予期せぬエラーによる整合性崩壊を防ぐためのトランザクション的処理
On Error GoTo ErrorHandler
Application.Calculation = pjManual ‘ 計算負荷を避けるため手動設定へ
‘ 各タスクの制約条件を考慮しつつ開始日をシフト
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
‘ 完了しているタスクは対象外にするのが安全
If tsk.PercentComplete < 100 Then
' 制約タイプを確認し、不要な固定を避ける
If tsk.ConstraintType = pjMSRestrictNoEarlierThan Then
tsk.ConstraintDate = DateAdd("d", offsetDays, tsk.ConstraintDate)
End If
End If
End If
Next tsk
' 再計算を実行し、依存関係に基づいた整合性を確保
Application.Calculation = pjAutomatic
proj.Calculate
MsgBox "プロジェクト日程の再調整が完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Application.Calculation = pjAutomatic
End Sub
---
3. アーキテクトからの設計上の忠告
データベース連携の罠
外部のデータベース(ExcelやSQL Server)からスケジュールを流し込む際、「日付のフォーマット」と「カレンダー設定」に注意が必要だ。VBAが認識する日付と、Project内部のタスクカレンダーが持つ「稼働日」がずれると、週末を跨いだタスクが1日分ずれることが多々ある。
必ず `Application.ActiveProject.Calendar` を経由して稼働日判定を行う設計を推奨する。
保守性を高めるための設計指針
- マジックナンバーの排除: `ConstraintType` 等の定数は、必ずProjectの組み込み定数(`pj…`)を使用すること。
- ログの出力: 変更前後で開始日が変わるタスクをイミディエイトウィンドウに出力し、後から追跡できるようにせよ。
- Undoスタックの意識: 巨大なタスクリストを一括処理する場合、`Application.UndoClear` を使うと処理は早くなるが、ユーザーがミスに気づいた時に「戻る」が効かなくなる。プロダクション環境では注意が必要だ。
—
まとめ:ツールは「道具」ではなく「論理」である
VBAを書くということは、単にタスクを並べ替えることではない。プロジェクトマネジメントの論理構造をコードで再現することだ。今回示したコードは、単なる開始日の移動だが、これを応用すれば「特定のタスク群のみの期間変更」や「リソース負荷に応じた自動シフト」まで拡張可能だ。
「とりあえず動くコード」で満足せず、プロジェクトの計算エンジンと対話する意識を持ってほしい。そうすれば、あなたの書くツールは、単なる自動化スクリプトではなく、プロジェクトを成功に導く「信頼できる副操縦士」になるはずだ。
