マクロの記録を卒業しよう。MS Projectの「制約条件」を自動制御して、スケジュールの整合性を守る極意
こんにちは。現場で数々のプロジェクトを自動化してきた、あなたのエンジニア仲間です。
「マクロの記録」機能を使って、なんとか作業を自動化できた。そんな成功体験を持つ方も多いでしょう。でも、もしあなたが「Project VBAを使って、もっと複雑な、でも人間がやるとミスが起きそうなルールを自動化したい」と考えているなら、今がそのステップアップのタイミングです。
今日は、プロジェクト管理における「命綱」とも言えるマイルストーンの制約条件(Constraints)を、VBAでスマートに制御・検証する方法を伝授します。
「ただ日付を入れるだけ」のコードから、「スケジュールの整合性を守る」プロフェッショナルなコードへ。一歩踏み出してみましょう。
1. なぜ「手入力」ではいけないのか? 制約条件の罠
MS Projectは、単なるガントチャートではありません。タスク同士の依存関係(先行・後続)を計算する、非常に強力な「スケジュール計算エンジン」です。
ここで重要なのが「制約条件(Constraint)」です。
「このマイルストーンは、絶対にこの日に終わらなければならない」というルールを課すことを、専門用語で「制約を付与する」と言います。
しかし、手動で制約を付けていると、こんな事故が起こります。
1. 入力ミス: 「Must Finish On(指定日に終了)」を設定するつもりが、誤って「Start No Earlier Than(指定日より前には開始しない)」にしてしまった。
2. 矛盾の放置: 制約で「〇月〇日終了」と決めたのに、先行タスクが遅延して「〇月〇日以降」に押し出されてしまった。Projectは警告を出しますが、気づかずにスケジュールが崩壊する。
これらを防ぐには、「命名規則に基づいた自動適用」と「適用後の整合性チェック」をセットで行うツールが必要です。
2. 今回構築するツールの設計図
今回は、以下のような実務的な要件を満たすツールを作ります。
- ターゲット: タスク名が `”MS_”` で始まるマイルストーン(期間0のタスク)。
- アクション: それらのタスクに対し、特定の日付で「終了日固定(Must Finish On)」の制約を自動で付与する。
- 検証: 制約を付けた結果、先行タスクの影響などで「指定日」からズレていないか(矛盾がないか)をチェックする。
概念図
[タスク一覧]
│
├─ MS_設計完了 (Duration: 0) ──▶ [命名規則一致!] ──▶ 制約適用 (Must Finish On)
├─ MS_開発完了 (Duration: 0) ──▶ [命名規則一致!] ──▶ 制約適用 (Must Finish On)
└─ 作業A (Duration: 5d) ──▶ [対象外]
[検証フェーズ]
制約日 == 実際の終了日 ? ──▶ YES: OK / NO: 警告(スケジュール矛盾発生!)
3. 実装:マイルストーン制約管理エンジン
それでは、魂を込めたコードを見ていきましょう。このコードは、単に動くだけではなく、「エラーに強く、後から読みやすい」設計にしています。
Option Explicit
''' <summary>
''' 特定の命名規則を持つマイルストーンに対し、終了日制約を自動適用し、
''' スケジュールの整合性を検証する。
''' </summary>
Sub ApplyAndVerifyMilestoneConstraints()
Dim t As Task
Dim targetDate As Date
Dim milestonePrefix As String
Dim successCount As Integer
Dim errorCount As Integer
' --- 設定エリア ---
' 適用したい目標日(実務ではセルやダイアログから取得するのが理想)
targetDate = DateValue("2024/12/31")
' マイルストーンを特定するための接頭辞
milestonePrefix = "MS_"
' ------------------
successCount = 0
errorCount = 0
Debug.Print "--- 処理開始: " & Now & " ---"
' Project内の全タスクをループ
' ※ ActiveProject.Tasks は、空の行(Nothing)が含まれる可能性があるため注意
For Each t In ActiveProject.Tasks
' 1. オブジェクトの存在チェック(空行対策)
If Not t Is Nothing Then
' 2. 条件判定:名前が接頭辞で始まり、かつ期間が0(マイルストーン)か?
If t.Name Like milestonePrefix & "*" And t.Duration = 0 Then
On Error Resume Next ' 制約設定時の予期せぬエラーを回避
' 3. 制約の適用
' pjMustFinishOn: 指定した日に必ず終了しなければならない制約
t.ConstraintType = pjMustFinishOn
t.ConstraintDate = targetDate
' 4. 整合性の検証(ここがエンジニアの腕の見せ所)
' 制約を付けた結果、先行タスク等の影響で「実際の終了日」がズレていないか確認
' Projectの計算エンジンが再計算した後の t.Finish を見る
If t.Finish <> targetDate Then
' 制約と実際のスケジュールが矛盾している場合
Debug.Print "【警告】矛盾発生: '" & t.Name & "' は制約日(" & targetDate & ")に終了できません。実際の終了日: " & t.Finish
errorCount = errorCount + 1
Else
Debug.Print "【成功】適用完了: '" & t.Name & "'"
successCount = successCount + 1
End If
On Error GoTo 0 ' エラーハンドリングを戻す
End If
End If
Next t
' --- 結果レポート ---
MsgBox "処理が完了しました。" & vbCrLf & _
"適用成功: " & successCount & " 件" & vbCrLf & _
"矛盾検知: " & errorCount & " 件" & vbCrLf & _
"※矛盾がある場合は、先行タスクの遅延を確認してください。", vbInformation, "実行結果"
Debug.Print "--- 処理終了: " & successCount & "成功, " & errorCount & "エラー ---"
End Sub
4. プロの視点:ここをクリアすれば、Project VBAの基本はバッチリですよ
このコードを読み解く際、単なる「書き写し」で終わらせないために、以下の3つのポイントを意識してください。これこそが、初級者と中級者を分ける境界線です。
① `If Not t Is Nothing` の重要性
Projectのタスクリストには、ユーザーが削除した跡や、空の行が含まれることがあります。これに対してプロパティ(`.Name`など)にアクセスしようとすると、`Object variable or With block variable not set` というエラーで止まってしまいます。「オブジェクトのライフサイクル(存在確認)」を意識することは、堅牢なツールを作る第一歩です。
② 制約の種類(ConstraintType)の理解
今回は `pjMustFinishOn` を使いました。これは非常に強力な制約です。
- `pjAsSoonAsPossible` (ASAP): できるだけ早く(デフォルト)。
- `pjFinishNoLaterThan`: 指定日より遅くなってはならない(少し柔軟)。
- `pjMustFinishOn`: 指定日そのものでなければならない(非常に厳格)。
実務では、プロジェクトの性質に合わせてこれらを使い分ける必要があります。
③ 「適用」と「検証」を分けない
多くの初学者は「値をセットする」コードだけを書きます。しかし、プロのエンジニアは「セットした結果、正しく動いたか?」までをセットで設計します。
今回のコードのように、`t.Finish`(計算後の日付)と `targetDate`(設定した日付)を比較するロジックを入れることで、ツールが「ただの作業自動化」から「品質管理ツール」へと昇華します。
まとめ
いかがでしたか?
マクロの記録から一歩踏み出し、「条件判定」「制約の制御」「整合性の検証」というロジックを組み込むことで、VBAはあなたの強力な武器になります。
最初はエラーが出るかもしれません。でも、そのエラーこそがプロジェクトの矛盾を教えてくれる貴重なサインです。エラーを恐れず、一つずつロジックを組み立てていってください。
ここをクリアすれば、Project VBAの基本はバッチリですよ。応援しています!
