【Project VBA極限講座】リソース平準化と制約条件の「衝突」を制御する:エンジンの意志を読み解くプログラミング術
こんにちは。プロジェクト管理の現場で、日々「動かないスケジュール」と格闘している同志の皆さん。
マクロの記録から一歩踏み出し、自分でコードを書き始めた皆さんは、今まさに「Project VBAの深淵」の入り口に立っています。
「リソース平準化を実行したら、せっかく設定した制約条件(Must Start Onなど)が無視されたように見える」
「制約条件を守ろうとすると、リソースの重複が解消されない」
もしあなたが今、こんな壁にぶつかっているとしたら……おめでとうございます。あなたは「スケジュール計算エンジン」という、Project VBAにおける真のボスと対峙している証拠です。
今日は、単なるコードの書き方ではなく、「エンジンの計算ロジックをどうコントロールし、制約と平準化の矛盾を解くか」という、実務中級者への登竜門となる知見を伝授します。ここをクリアすれば、あなたの作るツールは「ただ動くもの」から「プロが信頼する武器」へと進化しますよ。
1. なぜ「衝突」は起きるのか?:エンジンの二面性
Project VBAを扱う上で、まず理解しなければならないのは、Projectには「ユーザーの意志(制約条件)」と「物理的な限界(リソース制約)」という、時に矛盾する二つのルールが存在しているということです。
制約条件(Constraints)とは
「このタスクは絶対に〇月〇日に始めなければならない(Must Start On)」といった、カレンダー上の絶対的なルールです。これはユーザーの「意志」です。
リソース平準化(Resource Leveling)とは
「同じ人が同時に2つの仕事はできない」という、物理的なリソースの限界に基づいた調整です。これはエンジンの「計算」です。
衝突のメカニズム:
あなたが「絶対にこの日に始めろ!」(制約)と命じても、その日にリソースがフル稼働していたら、エンジンはパニックを起こします。制約を優先すればリソースが重複し、リソースを優先すれば制約が破られる。この「板挟み」状態こそが、スケジュールが崩れる正体です。
2. 戦略的アプローチ:プロの解決策
賢いエンジニアは、エンジンと力ずくで戦いません。「エンジンの計算しやすいように、事前に条件を整えてあげる」のです。
具体的には、VBAを使って以下のロジックを組みます。
1. 検知: リソースが重複している(Overallocated)タスクを特定する。
2. 判断: そのタスクの制約条件が「硬すぎる(Hard Constraint)」かどうかを判定する。
3. 緩和: 必要に応じて、制約を「柔らかいもの(Soft Constraint)」へ自動的に変更するか、タスクの「優先順位(Priority)」を操作して、エンジンの計算順序を誘導する。
3. 実装:制約条件を動的に調整するVBAエンジン
それでは、具体的なコードを見ていきましょう。このコードは、リソースが重複しているタスクを見つけ、その制約条件が「Must Start On(絶対開始日)」のように強すぎる場合、それを「Start No Earlier Than(~より前には開始しない)」に緩和し、優先順位を調整するものです。
Option Explicit
''' <summary>
''' リソース平準化と制約条件の競合を解消するための優先順位調整ロジック
''' </summary>
Sub ResolveConstraintConflicts()
Dim t As Task
Dim proj As Project
Set proj = ActiveProject
' 【極意1】計算モードを「手動」にする
' ループ内でタスクを書き換えるたびに再計算が走ると、パフォーマンスが劇的に低下し、
' 最悪の場合、計算途中の不安定な状態でエラーになります。
proj.Calculation = pjManual
On Error GoTo ErrorHandler
Debug.Print "--- 調整プロセス開始 ---"
' 全タスクをループ
For Each t In proj.Tasks
' 空のタスクやサマリータスクはスキップ
If Not t Is Nothing Then
If Not t.Summary Then
' 【極意2】リソースが重複しているタスクをターゲットにする
If t.ResourceOverallocated Then
Debug.Print "重複検知: " & t.Name
' 制約条件の判定
' pjTaskMustStartOn (絶対開始日) は非常に強力で、平準化を阻害する最大の要因
If t.ConstraintType = pjTaskMustStartOn Then
Debug.Print " -> 制約を緩和中: Must Start On -> Start No Earlier Than"
' 制約を「~より前には開始しない」に緩和
t.ConstraintType = pjTaskStartNoEarlierThan
' 元の開始日を維持しつつ、エンジンの計算に「遊び」を与える
t.Start = t.Start
End If
' 【極意3】優先順位(Priority)による制御
' 制約を緩めるだけでなく、優先順位を上げることで、
' 平準化計算時に「先にこのタスクを確保する」ようエンジンに促す
If t.Priority < 1000 Then
t.Priority = 1000 ' 優先度を高く設定
Debug.Print " -> 優先度を上昇させました。"
End If
End If
End If
End If
Next t
' 全ての調整が終わったら、一括で再計算を実行
proj.Calculation = pjAutomatic
Msgprint "調整が完了しました。リソース平準化を実行してください。"
CleanUp:
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanUp
End Sub
コードの解説:ここが「プロ」の視点です
# ① `proj.Calculation = pjManual` の魔法
初心者がやりがちなミスが、ループの中でタスクのプロパティを次々と書き換えることです。Projectは1つプロパティが変わるたびに、全スケジュールを計算し直そうとします。これでは処理が終わりません。「一気に書き換えて、最後に一回だけ計算させる」。これが、大規模なプロジェクトを扱う際の鉄則です。
# ② `ConstraintType` の使い分け
`pjTaskMustStartOn` は、エンジンの動きを完全にロックしてしまいます。これを `pjTaskStartNoEarlierThan` に変えるだけで、エンジンは「あ、この日以降なら、リソースが空いている時に動かしてもいいんだな」と判断できるようになります。これが「制約の緩和」です。
# ③ `Priority` によるエンジンの誘導
平準化エンジンは、タスクの「優先度」を見て、どのタスクを先に配置するかを決めます。制約を緩めたタスクの優先度を上げることで、スケジュールが後ろにズレるのを最小限に抑えつつ、リソースの空き時間を埋めることができます。
4. 陥りやすいエラーと回避策
このロジックを実装する際に、以下の点には注意してください。
- 無限ループのような挙動:
制約を緩めるロジックが強すぎると、意図しないタスクまで次々と制約が変わってしまうことがあります。必ず「リソースが重複している場合のみ」という条件を厳密に。
- データの喪失:
`ConstraintType` を変更することは、ユーザーが入力した「意志」を上書きすることです。実務では、変更前に「元の制約条件」をカスタムプロパティなどにバックアップしておくのが、一流のエンジニアの作法です。
- サマリータスクへの干渉:
サマリータスク(親タスク)に対して制約や優先度を操作すると、計算が複雑化して予期せぬ挙動をすることがあります。必ず `If Not t.Summary Then` で、作業タスクのみを対象にしましょう。
まとめ:エンジンの「意志」を理解して、真の自動化へ
Project VBAの真髄は、単にセルやプロパティを書き換えることではありません。「Projectの計算エンジンが、どういう理屈でスケジュールを動かしているか」を理解し、その動きを先回りして制御することにあります。
今回紹介した「制約の緩和」と「優先順位の調整」は、その第一歩です。
これをマスターすれば、あなたは「ツールを作れる人」から、「プロジェクトの成功をエンジニアリングできる人」へとステップアップできるはずです。
さあ、恐れずにコードを書いて、エンジンの制御に挑んでみてください。応援していますよ!
