Project VBAを掌握する:破綻なきタスク制御と「Undoスタック」の設計思想
MS ProjectのVBA開発において、最も多くのエンジニアが犯す致命的なミスをご存知だろうか。それは「単一のタスク更新を逐次的に実行し、エラーハンドリングを怠ること」だ。
WBSの階層構造、依存関係、制約条件。これらは全て相互にリンクしている。一箇所でも不正な値を流し込めば、プロジェクト全体が不整合を起こし、取り返しのつかないデータ破壊を招く。特に、外部DBやCSVから一括インポートするようなツールにおいて、「Undo(元に戻す)スタックの制御」は、単なる機能ではなく「プロダクトの信頼性そのもの」である。
今回は、伝説的アーキテクトの視点から、VBAで堅牢なトランザクションを疑似構築する極限の手法を伝授する。
—
1. なぜVBA標準の「Undo」は当てにならないのか
MS ProjectのVBAには、SQLのような`BEGIN TRANSACTION`や`ROLLBACK`命令は存在しない。`Application.Undo`はあくまでユーザーの操作をスタックするものであり、マクロの実行単位は「一つの大きなUndo単位」として処理されることもあれば、処理内容によってはスタックが分断されることもある。
「なぜそのコードは危険なのか?」
- 非アトミックな処理: ループの途中でエラーが発生し、処理が中断されたとき、ゴミデータがWBSに残る。
- 再計算コストの爆発: タスクを一括変更する際、`Calculate`が内部で無数に走り、パフォーマンスを著しく低下させる。
—
2. 実践的設計パターン: 「ステージング&一括コミット」
エラー時にプロジェクトを汚さないための黄金律は、「計算負荷の高い処理は極力遅延させ、検証プロセスを通過したものだけを実データに適用する」ことだ。
プロダクションコード:セーフ・トランザクション設計
以下のコードは、タスクの依存関係を更新する際に、検証→適用→エラーハンドリングを完遂するテンプレートだ。
‘ プロジェクトの整合性を保つためのトランザクション・ラッパー
Public Sub SafeUpdateTaskDependency(targetTaskID As Long, predecessorID As Long)
Dim proj As Project
Set proj = ActiveProject
‘ 1. パフォーマンス最適化:自動計算を一旦停止
Dim calcMode As Long
calcMode = Application.Calculation
Application.Calculation = pjManual
On Error GoTo RollbackHandler
‘ 2. バリデーション:ここにビジネスロジックを配置
‘ 不整合な依存関係を作らせないためのガード節
If targetTaskID = predecessorID Then Err.Raise 1001, , “循環参照の検知”
‘ 3. 実行(メイン処理)
Dim t As Task
Set t = proj.Tasks(targetTaskID)
t.Predecessors = predecessorID
‘ 4. コミット(一括計算)
Application.Calculation = calcMode
Application.Calculate
Exit Sub
RollbackHandler:
‘ 5. 安全な復旧
Application.Calculation = calcMode
MsgBox “更新中にエラーが発生しました。変更は破棄されます。” & vbCrLf & _
“エラー詳細: ” & Err.Description, vbCritical
‘ 必要に応じて、ここからログ出力やDB側のロールバック処理を呼び出す
End Sub
—
3. 開発現場で死なないための「鉄の掟」
① `Calculation`プロパティの制御
タスクを1000件更新する際、一行ごとに計算させてはならない。`Application.Calculation = pjManual` に設定し、最後に `Application.Calculate` を呼び出す。これがパフォーマンス維持と、更新の一貫性を保つ唯一の道だ。
② データベース連携時の落とし穴
外部DB(SQL ServerやAccess)と連携する場合、「VBA側のタスクID」と「DB側の主キー」を直結させてはならない。
MS ProjectのタスクIDは、行の削除や挿入で簡単に変わる。必ず `UniqueID` を介してマッピングし、処理の直前で常に最新のID状態をスキャンする仕組みを構築すること。
③ 「元に戻す」情報の保存
もしユーザーの操作を完全にロールバックしたいなら、処理前に「プロジェクトファイル(mpp)の一時的なスナップショット(名前を付けて保存)」を生成し、エラー発生時にそれを上書き復元するロジックを組み込むのが、最も原始的かつ確実な「Undoの実装」である。
—
結論:エンジニアの誇りとして
「とりあえず動くコード」と「プロダクション品質のコード」の差は、エラー発生時に何を残すかという一点に集約される。
Project VBAは古い言語だが、その背後にあるプロジェクト管理の理論は深遠だ。WBSを操作するということは、誰かの時間とリソースの未来を書き換えることに他ならない。
次にあなたがコードを書くとき、その「トランザクション」が失敗した瞬間の光景を想像してほしい。そこでゴミデータを撒き散らすのか、それとも静かに元の状態へ収束させるのか。
その判断ができる者だけが、真の業務自動化エンジニアと名乗れるのだ。
