こんにちは!Project VBAの世界へようこそ。
マクロの記録から一歩踏み出し、「現場で本当に使える自動化ツールを作りたい」と思っているあなたへ。
今回は、Project VBAにおける「スケジュール計算エンジンの制御」、その中でも一歩進んだ実務の壁――「制約条件とリソース平準化の競合をVBAで自動解決するロジック」について、徹底的に解説していきます。
「リソースを平準化したら、納期(制約)がズレてしまった…」
「ASAP(できる限り早く)で組んだはずなのに、人の割り当てのせいで勝手に先送りされた…」
プロジェクト管理の現場で、誰もが一度は頭を抱えるこのジレンマ。これをVBAの力でスマートに検出し、コントロールする方法を、伝説のチーフアーキテクトである私と一緒に紐解いていきましょう。ここをクリアすれば、あなたのVBAスキルは間違いなく一段上のステージに到達しますよ!
—
1. なぜ「制約条件」と「リソース平準化」はバチバチに競合するのか?
まず、MS Projectの頭の中(エンジンの挙動)を少しだけ覗いてみましょう。
- 制約条件(ASAP, ALAP, 「〇日以降に開始」など):
「このタスクは絶対にこの日までに終わらせろ!」という時間の絶対命令です。
- リソース平準化(Leveling):
「この人は同時に何個もタスクを抱えられないから、順番を後ろにずらそう」というリソースの物理的命令です。
Projectのエンジンは、リソース平準化を実行すると、人の空きを作るために平気でタスクを後ろにずらします。その結果何が起きるか? ユーザーが設定した「これ以上遅らせてはいけない制約(MSO:Must Start On など)」を、平気でブチ破ってしまうのです。
「おいおい、勝手に納期を延ばすなよ!」
「いやいや、人が足りないんだから仕方ないだろ!」
このエンジンの内部闘争を、VBAを使って「どちらを優先すべきか」自動で判定・調停するのが今回のミッションです。
—
2. 現場で使える!競合検出&自動調整エンジンの設計図
今回は、以下のロジックで動くVBAマクロを作成します。
1. 現状スキャン:すべてのタスクをループし、「制約の日付」と「平準化によって実際に動かされた開始日」を比較する。
2. 競合の検出:制約があるにもかかわらず、平準化によってスケジュールが後ろ倒しされている(= 制約違反が起きている)タスクをあぶり出す。
3. 優先度の判定と自動調整:あらかじめ決めたポリシー(例:「重要タスクなら制約を優先してリソースオーバーを許容」「通常タスクなら平準化を優先して制約を解除」)に基づき、コードでプロパティを書き換える。
—
3. 実装コード:競合解決モジュール
さあ、実際にコードを書いていきましょう。
開発タブからVisual Basic Editorを開き、標準モジュールに以下のコードを貼り付けてください。
‘ ==============================================================================
‘ モジュール名: ModResourceConstraintResolver
‘ 概要: リソース平準化による制約違反を検出し、優先度に応じて自動調整する
‘ ==============================================================================
Sub ResolveConstraintLevelingConflict()
Dim t As Task
Dim conflictCount As Long
conflictCount = 0
‘ 画面描画を停止して処理速度を爆発的に上げる(VBA最適化の基本!)
Application.ScreenUpdating False
On Error GoTo ErrorHandler
MsgBox “リソース平準化と制約条件の競合チェックを開始します。”, vbInformation, “処理開始”
‘ プロジェクト内の全タスクをループ
For Each t In ActiveProject.Tasks
‘ サマリータスクや削除済みタスクはスキップ
If Not t Is Nothing Then
If Not t.Summary And t.Active Then
‘ 【条件判定】
‘ 制約の種類が「柔軟ではない(ASAP/ALAP以外)」かつ
‘ 平準化によって「開始日(Start)」が「制約日(ConstraintDate)」より後ろに押し出されているか?
If IsHardConstraint(t.ConstraintType) Then
If t.Start > t.ConstraintDate Then
conflictCount = conflictCount + 1
‘ ログ出力(イミディエイトウィンドウに確認用に出力)
Debug.Print “【競合検出】ID: ” & t.ID & ” / 名称: ” & t.Name & _
” / 設定制約日: ” & t.ConstraintDate & ” / 実1開始日: ” & t.Start
‘ ==========================================================
‘ 【自動調停ロジック】
‘ ここでは「優先度(Priority)」が 700 以上(高重要度)のタスクは
‘ 「制約優先」とし、平準化の影響を無視して制約日通りに戻す。
‘ それ未満は「平準化優先」とし、制約を「できる限り早く(ASAP)」に変更する。
‘ ==========================================================
If t.Priority >= 700 Then
‘ — パターンA:制約を死守(納期絶対遵守) —
‘ タスクを強制的に制約日に戻す(※リソースオーバーは許容する)
t.Start = t.ConstraintDate
t.Notes = t.Notes & vbCrLf & “[VBA自動調整] 平準化による遅延を検知。重要度高のため制約日を死守しました。”
Else
‘ — パターンB:リソース平準化を死守(人員超過回避) —
‘ 納期遅延を許容し、制約条件を「ASAP」に変更してエンジンに順応させる
t.ConstraintType = pjConstraintASAP
t.Notes = t.Notes & vbCrLf & “[VBA自動調整] リソース平準化を優先。制約条件をASAPに変更しました。”
End If
End If
End If
End If
End If
Next t
Application.ScreenUpdating True
‘ 結果報告
MsgBox “チェック完了! ” & conflictCount & ” 件の競合を自動解決しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
Application.ScreenUpdating True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “致命的なエラー”
End Sub
‘ ——————————————————————————
‘ 補助関数: 指定された制約タイプが「硬い(ハード)制約」かどうかを判定する
‘ ——————————————————————————
Private Function IsHardConstraint(cType As PjConstraint) As Boolean
Select Case cType
Case pjConstraintMustStartOn, pjConstraintMustFinishOn, _
pjConstraintStartNoEarlierThan, pjConstraintFinishNoEarlierThan, _
pjConstraintStartNoLaterThan, pjConstraintFinishNoLaterThan
IsHardConstraint = True
Case Else
IsHardConstraint = False
End Select
End Function
—
4. コードの深掘りポイント(ここがプロの知見)
初心者から一歩抜け出すために、このコードに込めた「エンジニアとしてのこだわり」をいくつか解説します。
① `Application.ScreenUpdating False` の重要性
Project VBAで最もやってはいけないのが、ループの中で毎回ガタガタとガントチャートを再描画させることです。タスクが1,000件あったら、画面描画だけで何分もかかります。最初に画面をフリーズさせ、裏側で一瞬で計算を終わらせる。これが大規模プロジェクトを扱うプロの常識です。
② ハード制約のフィルタリング (`IsHardConstraint`)
MS Projectには「できる限り早く(ASAP)」や「できる限り遅く(ALAP)」といった、スケジュールに柔軟性を持たせるソフト制約があります。これらは平準化で動いても問題ありません。
プログラミングでは、「本当に守らなければならない硬い制約(MSO, MFO, SNETなど)」だけを関数で正確にフィルタリングするのが、バグを防ぐ秘訣です。
③ 現場のポリシーに合わせた「分岐」
コード内の `t.Priority >= 700` という条件部分に注目してください。
すべてのタスクを一律に扱うのではなく、「経営に直結する重要タスクは納期(制約)を死守」「一般タスクは人の都合(平準化)を優先」というビジネスの判断基準をコードに落とし込んでいる点こそ、自動化エンジニアの真骨頂です。
—
5. 陥りやすい罠とエラー回避の心得
実際にこのコードを運用する際、初心者がハマりがちなポイントを先回りして伝授しておきます。
- 「無限ループ」の罠に注意する
タスクの開始日をコードから無理やり書き換えると、MS Projectのスケジュールエンジンが再計算走り、別のタスクに影響を与えて連鎖的に日付が変わることがあります。イベントプロシージャ(`Project_Change`など)の中でこれをやると、最悪の場合フリーズします。必ず標準モジュールから手動(またはボタン押下)で実行する設計にしてください。
- タスクの `Nothing` 判定を怠らない
Projectの `Tasks` コレクションは、途中でタスクが削除されると「穴あき」状態になり、`Nothing` が返ることがあります。これをサボると `Object variable or With block variable not set`(実行時エラー91)という、初心者が泣くエラーの定番を踏み抜くことになります。上記のコードでは `If Not t Is Nothing Then` でしっかりとガードしています。
—
まとめ:ここをクリアすれば、Project VBAの基本はバッチリですよ!
お疲れ様でした!今回は、スケジュール計算エンジンの最大の難所である「制約条件とリソース平準化の衝突」をVBAで制御する方法を解説しました。
- エンジンの挙動(時間命令 vs 人員命令)を理解する
- `ScreenUpdating` でパフォーマンスを担保する
- 条件を正確に絞り込み、ビジネスロジックで調停する
この3つが頭に入っていれば、もう「マクロの記録を貼り付けるだけの人」ではありません。あなたは立派なProject自動化エンジニアです。
現場のプロジェクトマネージャーたちが頭を悩ませている面倒な調整作業を、あなたが書いたこの数行のコードでスマートに解決してあげてください。きっと社内で「おっ、できるな!」と評価されるはずです。
それでは、次回の極限の知見でお会いしましょう。ハッピー・コーディング!
