【テクニカル・上級編】初心者向け:タスクの「制約なし」状態をVBAで判定し、デフォルト値へ置換する – Project VBA解析バイブル

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

制御不能なスケジュールを、数学的必然へと変える――Project VBAにおける制約条件(Constraint)の完全掌握

プロジェクト管理の世界において、スケジュールは「願望」であってはならない。それは、依存関係とリソースの制約に基づいた「数学的必然」であるべきだ。

しかし、実務の現場ではどうだろうか。ユーザーが不用意にタスクに「開始前指定」や「終了後指定」といった制約(Constraint)を打ち込み、プロジェクト全体のクリティカルパスを破壊している光景を、私は何度見てきたことか。

本稿では、初心者向けのテーマである「タスクの制約条件を判定し、デフォルト(ASAP: As Soon As Possible)へ置換する」という処理を題材に、単なるコードの書き方を超えた、エンジニアリングとしてのスケジューリング制御の真髄を解説する。

1. 概念の再定義:制約条件(Constraint)とは何か

多くの初学者は、制約条件を単なる「カレンダー上の設定」だと誤解している。だが、アーキテクトの視点では、制約条件は「スケジューリングエンジン(CPM: Critical Path Method)に対する、論理的強制力」である。

MS Projectの計算エンジンは、タスク間の「先行・後続関係(Dependency)」を基に、フリーフロート(余裕期間)を計算する。しかし、タスクに `pjTaskConstraintStartNoEarlierThan`(開始前指定)などの制約が付与された瞬間、そのタスクは論理的な依存関係から切り離され、エンジンによる動的な計算が阻害される。

これが、大規模プロジェクトにおいて「なぜかスケジュールが動かない」「計算が合わない」という怪現象を引き起こす正体だ。我々の任務は、これらの「不純な制約」を排除し、プロジェクトを純粋なロジックへと回帰させることにある。

2. パフォーマンスの罠:計算エンジンの制御

VBAでタスクをループ処理する際、最も致命的なミスは「プロパティを変更するたびに、MS Projectの再計算エンジンを起動させてしまうこと」だ。

タスクが1,000個あるプロジェクトで、1つずつ制約を変更し、その都度エンジンが再計算を行えば、計算量は $O(n^2)$ に近づき、アプリケーションは実質的にフリーズする。

これを防ぐためには、処理の開始時に計算モードを `Manual`(手動)に切り替え、全処理が完了した後に一度だけ `Automatic`(自動)に戻す。これは、レガシーなシステム間連携においても、トランザクションの整合性を保つための鉄則である。

3. 実装:最適化された制約置換ロジック

以下に、堅牢でパフォーマンスを考慮した実装例を示す。単なる `For Each` ではなく、オブジェクトのライフサイクルとエラーハンドリングを考慮したプロフェッショナルな構造だ。

Option Explicit

''' <summary>
''' プロジェクト内の全てのタスクを走査し、
''' ASAP(制約なし)以外の制約を持つタスクを、デフォルトの制約に一括置換する。
''' </summary>
Public Sub ResetTaskConstraintsToASAP()
    Dim pjApp As MSProject.Application
    Dim targetProj As MSProject.Project
    Dim t As MSProject.Task
    Dim changeCount As Long
    Dim calcModeBefore As MSProject.Calculation
    
    ' オブジェクトの参照取得
    Set pjApp = MSProject.Application
    Set targetProj = pjApp.ActiveProject
    
    ' 1. 計算モードのバックアップと一時停止
    ' プロパティ変更のたびに再計算が走るのを防ぐ(極めて重要)
    calcModeBefore = targetProj.Calculation
    targetProj.Calculation = pjCalculationManual
    
    On Error GoTo ErrorHandler
    
    changeCount = 0
    
    ' 2. タスクコレクションの走査
    ' コレクションの要素を直接操作する場合、インデックスによるループも検討すべきだが、
    ' 読み取り専用の判定であれば For Each が最も直感的かつ高速である。
    For Each t In targetProj.Tasks
        ' Nothingチェック(削除されたタスクや空のインデックス対策)
        If Not t Is Nothing Then
            
            ' 3. 制約条件の判定
            ' pjTaskConstraintAsSoonAsPossible (0) 以外を検知
            If t.ConstraintType <> pjTaskConstraintAsSoonAsPossible Then
                
                ' 制約の置換
                t.ConstraintType = pjTaskConstraintAsSoonAsPossible
                
                ' 制約に伴う日付の不整合を防ぐため、日付もリセットすることを推奨
                ' (制約を外しても、日付が固定されたままだと実質的な制約として残るため)
                ' t.Start = t.Start ' 必要に応じて論理的な再計算に任せる
                
                changeCount = changeCount + 1
            End If
            
        End If
    Next t

    ' 4. 計算モードの復元と強制再計算
    targetProj.Calculation = calcModeBefore
    targetProj.Calculate ' 最後に一度だけエンジンを回す
    
    MsgBox "処理完了。" & vbCrLf & _
           "置換されたタスク数: " & changeCount, vbInformation, "Architect Report"

CleanUp:
    ' 5. オブジェクトの明示的解放
    ' COMオブジェクトのライフサイクルを管理し、メモリリーク(ゾンビプロセス)を防ぐ
    Set t = Nothing
    Set targetProj = Nothing
    Set pjApp = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical, "System Error"
    Resume CleanUp
End Sub

4. 極限の知見:メモリ管理とCOMオブジェクトのライフサイクル

シニアエンジニアとして、コードの背後にある「メモリの挙動」を無視することはできない。

オブジェクトの解放(Destruction)

VBAは、変数のスコープが外れれば自動的に参照カウントを減らす。しかし、大規模な自動化ツールをExcelや外部アプリケーションから呼び出す場合、`Set t = Nothing` による明示的な解放を怠ると、MS Projectのプロセス(`MSProject.exe`)がタスクマネージャーに残り続ける「ゾンビプロセス」を引き起こす。これは、システム管理者が最も嫌う、リソースの枯渇原因だ。

Windows APIとの連携(将来的な拡張)

もし、この処理を数万タスク規模の超巨大プロジェクトで行う場合、VBAの標準的な `Timer` では精度が足りない。その場合は、`kernel32` の `GetTickCount64` 等を呼び出し、プロセスの実行時間をマイクロ秒単位で計測・プロファイリングすることで、ボトルネックが「オブジェクトへのアクセス」にあるのか、「エンジンによる計算」にあるのかを切り分ける必要がある。

5. まとめ:エンジニアとしての規律

「制約なし」の状態を作ることは、単なるデータのクリーニングではない。それは、プロジェクトを「決定論的なモデル」へと昇華させるプロセスである。

1. エンジンの制御を忘れるな: `Calculation = Manual` は、パフォーマンスにおける絶対的な規律である。
2. オブジェクトのライフサイクルを統制せよ: `Nothing` への代入は、システムの安定性を担保する作法である。
3. 論理的整合性を追求せよ: 制約を外した後の日付の挙動までを見据えてこそ、真のアーキテクトである。

技術は、単なる手段に過ぎない。その手段を、いかに正確に、いかに効率的に、いかに美しく制御するか。そこにこそ、プロフェッショナルの価値が宿るのだ。

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