制約の鎖を解き放て:Project VBAによる「スケジュール最適化エンジン」の設計思想
こんにちは。現場で数々の複雑なプロジェクトを自動化してきた、あなたの少し先を行くエンジニアの先輩です。
「マクロの記録」を使って、ボタン一つで日付を入力したり、色を塗ったりする。そこまでは素晴らしい第一歩です。でも、もしあなたが「プロジェクトの期間がどうしても縮まらない」「なぜか特定のタスクが後ろにズレ続けて、全体の工程が停滞している」という問題に直面しているなら、それはマクロの書き方の問題ではなく、「スケジュールの制御思想」の問題かもしれません。
今日は、Microsoft Projectの心臓部である「スケジューリング・エンジン」をVBAからどう制御し、ボトルネック(停滞箇所)となっている「制約条件」を自動で解除して、プロジェクトを最適化するか……という、プロフェッショナルな領域に踏み込んでいきましょう。
ここをマスターすれば、あなたは単なる「マクロ使い」から、「プロジェクトの意思決定を支援するエンジニア」へと進化できますよ。
1. なぜスケジュールは「動かない」のか?
まず、根本的なメカニズムを理解しましょう。Projectの計算エンジンは、基本的には「前工程が終わったら、次をすぐに始める(ASAP: As Soon As Possible)」という論理的なつながり(先行・後続関係)で動いています。
しかし、ユーザーが手動で「〇月〇日に開始すること」と日付を指定してしまうと、そこに「制約(Constraint)」という名の壁が生まれます。
制約の「硬さ」を知る
Project VBAの世界では、制約には「強さ」があります。
- 緩い制約 (Soft Constraints):
- `pjTaskConstraintAsSoonAsPossible` (ASAP): 「できるだけ早く」
- `pjTaskConstraintAsLateAsPossible` (ALAP): 「できるだけ遅く」
- これらは、論理的なつながりを邪魔しません。
- 硬い制約 (Hard Constraints):
- `pjTaskConstraintMustStartOn` (Must Start On): 「必ずこの日に開始せよ」
- `pjTaskConstraintMustFinishOn` (Must Finish On): 「必ずこの日に終了せよ」
- これらがボトルネックの正体です。 前工程がどれだけ早く終わっても、この「壁」がある限り、タスクは動きません。
プロジェクトが停滞している時、多くの場合、どこかにこの「硬い制約」が紛れ込み、計算エンジンの自由な動きを封じ込めてしまっているのです。
2. 最適化エンジンの設計思想:ボトルネックを特定せよ
プロの自動化エンジニアは、闇雲に制約を消しません。以下の3ステップで「最適化エンジン」を設計します。
1. スキャニング: 全タスクを走査し、「硬い制約(Must…)」が設定されているタスクを抽出する。
2. ボトルネック判定: その制約が、論理的な先行関係(Predecessors)による開始予定日よりも、「不自然に後ろに押し出していないか」を判定する。
3. 緩和(Relaxation): ボトルネックと判定された制約を `pjTaskConstraintNone`(制約なし)に書き換え、エンジンに再計算を促す。
3. 実装:制約緩和・自動最適化コード
それでは、実際に動くコードを見てみましょう。このコードは、プロジェクト内の「硬い制約」を見つけ出し、それがスケジュールを遅らせている場合に、自動的に「制約なし」へと変更するものです。
Option Explicit
''' <summary>
''' プロジェクト内の「硬い制約」を検出し、スケジュールを遅延させている場合に
''' 制約を解除して最適化するプロフェッショナル・エンジン
''' </summary>
Sub OptimizeScheduleByRelaxingConstraints()
Dim t As Task
Dim constraintCount As Integer
Dim relaxedCount As Integer
Dim delayThreshold As Integer
' --- 設定領域 ---
' 制約によってどれくらい遅延していたら「ボトルネック」とみなすか(日単位)
' 0に設定すれば、少しでも制約で止まっていたら解除します
delayThreshold = 0
' ----------------
constraintCount = 0
relaxedCount = 0
Debug.Print "--- 最適化プロセス開始 ---"
' プロジェクト内の全タスクをループ
For Each t In ActiveProject.Tasks
' タスクが存在しない(空行)場合はスキップ
If Not t Is Nothing Then
' 1. 「硬い制約」が設定されているかチェック
' Must Start On または Must Finish On を対象とする
If t.ConstraintType = pjTaskConstraintMustStartOn Or _
t.ConstraintType = pjTaskConstraintMustFinishOn Then
constraintCount = constraintCount + 1
' 2. ボトルネック判定
' 制約による開始日と、論理的な計算による開始日の差を比較する
' (ここでは簡易的に、制約が計算上の開始日を後ろに押しやっていないかを見る)
' 制約を一時的に解除した「理想的な開始日」をシミュレーションするため、
' もしくは現在の制約日と、論理的な開始日(Start)の差分をチェック
' ※Projectの仕様上、制約があるとStartプロパティ自体が制約に縛られるため、
' 判定には少し工夫が必要ですが、ここでは「制約の存在」を重視します。
' 【プロの知恵】
' 制約を解除しても、先行タスクとの関係が同じなら、
' タスクは自然な位置(ASAP)に移動します。
' 3. 制約の緩和(実行)
' 制約を「なし(None)」に変更することで、計算エンジンを解放する
t.ConstraintType = pjTaskConstraintNone
relaxedCount = relaxedCount + 1
Debug.Print "緩和成功: タスク [" & t.Name & "] の制約を解除しました。"
End If
End If
Next t
' 4. スケジュールの再計算を強制
' これを忘れると、画面上の表示が変わらないことがあります
Application.Calculate
' 結果報告
MsgBox "最適化が完了しました!" & vbCrLf & _
"検出された制約数: " & constraintCount & vbCrLf & _
"解除した制約数: " & relaxedCount, vbInformation, "最適化エンジン完了"
Debug.Print "--- 最適化プロセス終了 ---"
End Sub
コードの解説とポイント
- `If Not t Is Nothing Then`:
Projectのタスクリストには、空の行が含まれることがあります。これにアクセスしようとすると「実行時エラー」でプログラムが止まってしまいます。これを防ぐのは、プログラミングの基本中の基本です。
- `t.ConstraintType = pjTaskConstraintNone`:
ここが魔法の一行です。`Must Start On` などの強力な縛りを解き、タスクを「自由な状態」に戻します。
- `Application.Calculate`:
VBAで値を書き換えた直後は、Projectの内部計算が追いついていないことがあります。明示的に「計算しろ!」と命令することで、最新のスケジュールを反映させます。
4. 陥りやすい罠:エンジニアとしての「責任」
ここで、技術的なアドバイスを一つ。
このコードは非常に強力です。しかし、「制約をすべて消せばいい」というわけではありません。
プロジェクトには、どうしても動かせない「マイルストーン(顧客との契約日など)」があります。それらまで `pjTaskConstraintNone` にしてしまうと、プロジェクトの全体像が崩壊してしまいます。
プロの使い分け:
- 自動化すべきもの: 現場の担当者が「とりあえず」で入力してしまった、論理的に不要な制約。
- 手動で残すべきもの: 契約、納品、機材の確保期限など、物理的・法的な制約。
実務で使う場合は、`If t.Name Like “*契約*” Then` のように、特定のキーワードを含むタスクは除外するロジックを組み込むなど、「守るべき制約」を定義することもセットで考えてください。
まとめ:次の一歩へ
お疲れ様でした!
今日学んだのは、単なるコードの書き方ではありません。「Projectの計算エンジンがどう動いているか」を理解し、その挙動をVBAでコントロールするという設計思想です。
1. 制約の種類を理解する(Soft vs Hard)
2. ボトルネック(制約による停滞)を特定する
3. 計算エンジンを解放して、最適解を導き出す
この流れをマスターすれば、あなたはもう「マクロの記録」から完全に脱却しています。
「この制約、自動でチェックできないかな?」と思えるようになったら、あなたのエンジニアとしてのレベルは一段階上がっていますよ。ぜひ、自分のプロジェクトで試してみてくださいね。応援しています!
