【入門編】【プロ向け】制約条件の「強制解除」によるスケジュール最適化とボトルネック解消 – Project VBA解析バイブル

スポンサーリンク
スポンサーリンク

制約の鎖を解き放て: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. 計算エンジンを解放して、最適解を導き出す

この流れをマスターすれば、あなたはもう「マクロの記録」から完全に脱却しています。

「この制約、自動でチェックできないかな?」と思えるようになったら、あなたのエンジニアとしてのレベルは一段階上がっていますよ。ぜひ、自分のプロジェクトで試してみてくださいね。応援しています!

タイトルとURLをコピーしました