【実務・中級編】【初心者向け】VBAによる制約条件の一括削除と、プロジェクトの完全ASAP化 – Project VBA解析バイブル

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

鎖を解き放て:Project VBAによる制約条件の完全排除とASAPスケジュールへの強制リセット

プロジェクトマネジメントの現場において、MS Projectのスケジュールが「動かない」ほど絶望的な状況はない。

タスクを動かそうとしても、なぜか特定の日付に張り付いて動かない。クリティカルパスが計算と合致しない。原因の多くは、現場の人間が「とりあえず」で設定した、制約条件(Constraints)の蓄積にある。Must Start On, Start No Earlier Than… こうした制約は、スケジュールの柔軟性を奪う「鎖」だ。

本記事では、複雑化したプロジェクトを、開始日基準の最短スケジュール(ASAP: As Soon As Possible)へと一瞬で解き放つ、堅牢なエンジニアリング手法を伝授する。単なる「コードの書き方」ではない。オブジェクトの挙動を支配するための「設計思想」を語ろう。

1. なぜ、初心者のコードは「壊れる」のか

多くの初心者は、以下のようなコードを書く。

' 避けるべき、脆弱な実装例
Sub BadReset()
    Dim t As Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            t.ConstraintType = pjConstraintNone ' 制約を消すだけ
        End If
    Next t
End Sub

これでは、プロフェッショナルの現場では通用しない。なぜか?

1. 計算エンジンの無視: 制約を消しただけでは、MS Projectの計算エンジンが「いつ」再計算を行うかが不安定だ。
2. エラーハンドリングの欠如: `Tasks` コレクションには、削除済みのタスクや、特殊なオブジェクトが混在することがある。`Nothing` チェックだけでは不十分だ。
3. パフォーマンスの欠如: 大規模プロジェクト(数千タスク)において、画面更新を制御せずにループを回すのは、リソースの無駄遣いである。
4. 状態の不整合: 制約を消しても、タスクの「開始日」自体に「手入力された値」が残っている場合がある。これは制約とは別の「手動スケジュール」状態を引き起こす。

2. アーキテクチャ設計:堅牢なリセット・プロセス

真に実務で使えるツールを作るには、以下の3つのレイヤーで設計を考えるべきだ。

Layer 1: 環境制御(Environment Control)

計算負荷を下げるため、`ScreenUpdating` を停止し、プロジェクトの計算モードを一時的に「手動」に切り替える。これにより、ループ中の再計算によるオーバーヘッドを極限まで削る。

Layer 2: 状態遷移(State Transition)

制約(Constraint)を排除するだけでなく、タスクのスケジュールモードを「自動(Auto Scheduled)」へと強制的に遷移させる。これにより、制約の有無に関わらず、先行・後続関係に基づくASAP計算が有効になる。

Layer 3: 整合性検証(Integrity Verification)

処理終了後、計算エンジンを強制的に「自動」で再起動させ、プロジェクト全体の整合性を保証する。

3. プロダクション・コード:Project ASAP Reset Engine

以下に、私が実務で推奨する、保守性と堅牢性を極限まで高めたコードを示す。これをそのまま、あるいはプロジェクトの文脈に合わせて調整して使用してほしい。

Option Explicit

''' <summary>
''' プロジェクト内の全タスクの制約条件を解除し、
''' プロジェクト開始日基準のASAPスケジュールへリセットする。
''' </summary>
Public Sub ResetProjectToASAP()
    Dim pj As MSProject.Application
    Set pj = MSProject
    
    Dim t As MSProject.Task
    Dim taskCount As Long
    Dim successCount As Long
    Dim errorCount As Long
    
    ' --- 1. 環境の最適化 (Performance Optimization) ---
    On Error GoTo ErrorHandler
    pj.ScreenUpdating = False
    ' 計算モードを「手動」にすることで、ループ中の再計算負荷を最小化する
    pj.Calculation = pjManual
    
    ' --- 2. 実行前確認 (Safety Check) ---
    ' 誤操作防止のため、ユーザーに最終確認を促す(実運用ではログ出力に置き換えることも検討)
    If MsgBox("全タスクの制約を解除し、ASAPスケジュールへリセットしますか?" & vbCrLf & _
              "この操作は取り消せません。", vbQuestion + vbYesNo, "実行確認") <> vbYes Then
        Exit Sub
    End If

    ' --- 3. メイン・ロジック (Core Logic) ---
    taskCount = pj.ActiveProject.Tasks.Count
    successCount = 0
    errorCount = 0

    For Each t In pj.ActiveProject.Tasks
        ' タスクが存在しない(削除済み等)場合はスキップ
        If Not t Is Nothing Then
            On Error Resume Next ' 個別のタスクエラーで全体を止めない
            
            ' 制約を「なし(None)」に設定
            t.ConstraintType = pjConstraintNone
            
            ' スケジュールモードを「自動(Auto Scheduled)」に強制
            ' これにより、制約なしの状態でのASAP計算が正しく機能する
            t.Manual = False
            
            If Err.Number = 0 Then
                successCount = successCount + 1
            Else
                errorCount = errorCount + 1
                Debug.Print "Error on Task: " & t.Name & " - " & Err.Description
            End If
            On Error GoTo ErrorHandler ' エラーハンドリングを戻す
        End If
    Next t

    ' --- 4. 整合性の復元 (Engine Synchronization) ---
    ' 計算モードを「自動」に戻し、全タスクの再計算を強制実行
    pj.Calculation = pjAutomatic
    pj.ScreenUpdating = True

    MsgBox "リセット完了" & vbCrLf & _
           "処理タスク数: " & taskCount & vbCrLf & _
           "成功: " & successCount & vbCrLf & _
           "失敗: " & errorCount, vbInformation, "完了"

    Exit Sub

ErrorHandler:
    ' 異常事態が発生した場合は、必ず環境を復元して終了する
    pj.ScreenUpdating = True
    pj.Calculation = pjAutomatic
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical, "System Error"
End Sub

4. エンジニアとしての警告:外部連携とデータ整合性

このマクロを「業務システム」の一部として組み込む場合、以下の2点に細心の注意を払わなければならない。

① データベース・外部ファイル連携の罠

もし、このMS ProjectファイルがSQL Serverなどのデータベースと同期されている、あるいは他のExcelファイルから値を参照している場合、この一括更新は「大量のトランザクション」を発生させる。

  • 対策: データベースへの書き込み(Sync)が走る前にこのマクロを実行するか、あるいは同期プロセスを一時的に無効化する設計にせよ。一気に数千行の変更がデータベースに飛ぶと、ロック競合やタイムアウトの原因となる。

② 「制約の削除」は「情報の破壊」でもある

制約(Constraint)は、時に「物理的な制約(例:機材がこの日にしか入らない)」を表現するために意図的に設定されている。

  • 設計思想: このマクロを「汎用ツール」として配布する場合、必ず「制約を消して良いタスク」と「消してはいけないタスク」を分けるフラグ(例:カスタムフィールドの「Reset対象」フラグ)を導入することを検討せよ。「何でも消す」のは、エンジニアリングではなく、ただの破壊だ。

結論

MS Project VBAにおける真のマスターとは、単にコードが書ける者ではない。オブジェクトのライフサイクルを理解し、計算エンジンの挙動を制御し、システム全体の副作用を予測できる者を指す。

今回のコードは、その第一歩だ。この堅牢なテンプレートを基に、君自身の業務に合わせた「最強の自動化ツール」を構築してほしい。

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