Project VBAの深淵:タスクの「実績保護」を自動化するアーキテクチャ設計
プロジェクト管理において、VBAでタスク依存関係を操作している諸君。単に`Task.Predecessors`を書き換えるだけのスクリプトで満足していないだろうか?
「完了したタスクのリンクが後から勝手に書き換わっていた」——これは大規模プロジェクトにおける最大級のアンチパターンだ。タスクが完了(%完了=100%)した時点で、その依存関係は「歴史的な実績」として封印されねばならない。
今回は、Project VBAのオブジェクトモデルを逆手に取り、完了したタスクの依存関係を「読み取り専用」としてガードする、堅牢な制御ロジックを伝授する。
—
1. なぜ「ガード」が必要なのか?(設計思想)
VBAによる自動化で最も恐ろしいのは、再帰的な依存関係の再計算や、うっかりとしたループ処理によるデータの汚染だ。特に、`Task.Predecessors` プロパティは強力だが、一度書き込むと元の状態には戻せない。
プロの設計原則:
- イミュータブル(不変)な実績: 完了(100%)したタスクは、いかなる自動化スクリプトからも「編集不可」にする。
- 防御的プログラミング: ロジック内で判定するのではなく、タスクのプロパティ(`Flag`や`CustomField`)を利用して、UIレベルの制御と同期させる。
—
2. 実装コード:完了タスクの依存関係保護
以下のコードは、Projectのタスクを走査し、`PercentComplete`が100%のタスクに対して、依存関係の書き込みを制限するためのトリガーを設ける仕組みだ。
‘ ———————————————————
‘ Module: TaskGuardManager
‘ 完了したタスクの依存関係を「実績」として保護する
‘ ———————————————————
Option Explicit
Public Sub ProtectCompletedTasks()
Dim tsk As Task
Dim proj As Project
Set proj = ActiveProject
‘ パフォーマンス向上のため、計算を一時停止
Application.Calculation = pjManual
On Error GoTo ErrorHandler
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
‘ 100%完了しているタスクを特定
If tsk.PercentComplete = 100 Then
‘ フラグフィールド(Flag1)を保護フラグとして使用する運用を推奨
‘ 実際に書き込みを制御する場合は、このフラグをチェックするロジックを
‘ 全ての依存関係操作スクリプトに組み込むことが重要
tsk.Flag1 = True
‘ 必要に応じてタスクのロック状態を制御
‘ (注:Projectには純粋なRead-Onlyプロパティは存在しないため、
‘ 自作のバリデーション関数を経由させる設計が必須)
Debug.Print “Protected Task: ” & tsk.Name
End If
End If
Next tsk
Application.Calculation = pjAutomatic
Exit Sub
ErrorHandler:
Application.Calculation = pjAutomatic
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub
‘ — 依存関係を書き込む際のバリデーション関数 —
‘ この関数を全ての書き込み処理の前段に置くこと
Public Function CanEditDependencies(tsk As Task) As Boolean
If tsk.Flag1 = True Then
MsgBox “エラー: タスク ‘” & tsk.Name & “‘ は完了済みのため、依存関係の変更は禁止されています。”, vbExclamation
CanEditDependencies = False
Else
CanEditDependencies = True
End If
End Function
—
3. 実務で「バグ」を生ませないための3つの鉄則
① 「計算の自動化」を制御せよ
`Application.Calculation = pjManual` を使わずに数千行のタスクをループさせれば、Projectはタスクを更新するたびに再計算を行い、処理速度は劇的に低下する。大規模な自動化では、「更新時」ではなく「一括反映時」に計算させるのが鉄則だ。
② 外部連携は「中間テーブル」を経由させよ
ExcelやDBからタスク情報を読み込んで依存関係を更新する場合、「直接Projectに流し込む」のは避けるべきだ。
一度VBA内のコレクション(`Scripting.Dictionary`等)に展開し、矛盾がないかバリデーションを通してから、最後に一括で`Task.Predecessors`へ書き込む。このバッファ構造こそが、データ破損を防ぐ唯一の策である。
③ プロパティの「副作用」を知る
`Task.Predecessors`に文字列を渡して設定する際、区切り文字やリンクの種類(FS, SS等)の解釈は環境に依存する。可能であれば、`TaskLink`オブジェクトを個別に生成・管理する手法をとることで、複雑な依存関係の解析を最小限に抑えることができる。
—
結論:コードは「契約」である
今回紹介した`CanEditDependencies`のようなバリデーション関数は、単なるヘルパーではない。これは「完了したタスクには手を触れない」という、開発チームとプロジェクト管理者の間の契約そのものだ。
自動化エンジニアの腕の見せ所は、いかに複雑な処理を書くかではない。「いかにして予期せぬ変更を防ぎ、システムを安定稼働させるか」という保守の視点にある。
諸君、まずは自身のプロジェクトで「Flag1」を保護フラグとして活用し、明日からの運用を変えてみてほしい。それが、伝説の自動化エンジニアへの第一歩だ。
