大規模プロジェクトの沈黙を破る:Project VBA カスタムフィールド計算の最適化術
こんにちは!業務自動化の世界へようこそ。
プロジェクトの規模が大きくなってくると、誰もが一度は直面する壁があります。それは、「MS Projectの動作が、まるで泥沼の中を歩いているかのように重くなる」という現象です。
「カスタムフィールドに数式を入れただけなのに」「タスクを一つ動かしただけで、画面がフリーズした……」
もしあなたが今、そんな悩みを抱えているとしたら、おめでとうございます。あなたは「マクロの記録」という初級ステージを卒業し、「オブジェクトの挙動を制御する」というプロフェッショナルな領域への入り口に立っています。
今日は、伝説的なアーキテクトが現場で実践している、カスタムフィールドの計算負荷を劇的に軽減する「極限の最適化手法」を伝授しましょう。
1. なぜ、あなたのプロジェクトは重くなるのか?
まず、敵の正体を知ることから始めましょう。
MS Projectには「カスタムフィールド」という非常に強力な機能があります。`Text1` や `Number1` といったフィールドに `[Duration] * 1.2` のような数式(Formula)を書き込むことができます。
これ自体は非常に便利ですが、大規模プロジェクト(タスク数が数千、数万に及ぶ場合)では、以下の「再計算の連鎖(Recalculation Loop)」が牙を剥きます。
【図解】再計算の悪循環
1. ユーザーの操作: タスクの期間を変更する。
2. エンジンの起動: MS Projectが「あ、データが変わった!再計算しなきゃ」と判断。
3. 数式の走査: すべてのタスクのカスタムフィールドに設定された数式を一つずつ評価。
4. 依存関係の連鎖: 数式の計算結果が変わったことで、さらに他の計算やスケジュールに影響が出る……。
5. CPUの悲鳴: このプロセスが、一つの変更に対して何度も、あるいは全タスクに対して何度も繰り返される。
つまり、「数式(Formula)は、便利だが『受動的』で制御不能な爆弾」なのです。
2. 最適化の極意: 「数式」から「値の書き込み」へ
プロフェッショナルなエンジニアは、こう考えます。
「Projectの計算エンジンに任せるのではなく、VBAで計算して『結果の値』だけを叩き込めばいい」
これを実現するための戦略が、「計算モードの制御」と「静的値への置き換え」です。
戦略のステップ
1. 計算を止める: `Application.Calculation = pjManual` で、プロジェクトの自動計算を一時停止します。
2. VBAで計算する: 数式で行っていた計算を、VBAのコード内で高速に処理します。
3. 結果を書き込む: 計算結果を、数式ではなく「ただのテキストや数値」としてカスタムフィールドに書き込みます。
4. 計算を再開する: 最後に `Application.Calculate` で、必要な部分だけを整合させます。
3. 実践: 劇的に速くなる最適化コード
それでは、具体的なコードを見てみましょう。
例えば、「タスクのコストとリスク係数を掛け合わせた『重み付きコスト』をカスタムフィールド(Number1)に算出する」というシナリオを想定します。
❌ 初心者がやりがちな「重い」コード
(数式が設定されたフィールドに対して、一つずつ値を読み書きしようとする、あるいは数式に頼り切るパターン)
✅ プロが書く「高速」な最適化コード
Sub OptimizeCustomFieldCalculation()
Dim t As Task
Dim startTime As Double
Dim taskCount As Long
' 実行時間の計測開始(パフォーマンス確認のため)
startTime = Timer
' --- [重要] ステップ1: 計算モードを「手動」に切り替える ---
' これにより、タスクを更新するたびに発生する自動再計算を封じ込めます
Application.Calculation = pjManual
On Error GoTo ErrorHandler
' プロジェクト内のタスクをループ処理
For Each t In ActiveProject.Tasks
' 空のタスク(サマリータスクの隙間など)はスキップ
If Not t Is Nothing Then
' --- [重要] ステップ2: VBA内で計算ロジックを完結させる ---
' カスタムフィールドに「数式」が入っているのではなく、
' ここで計算した「結果」を直接書き込むのがポイントです。
Dim riskFactor As Double
Dim baseCost As Double
' 例えば、Text1に「1.5」のようなリスク係数が入っていると仮定
' Val関数で数値に変換して計算
riskFactor = Val(t.Text1)
If riskFactor = 0 Then riskFactor = 1 ' 係数が空なら1とする
baseCost = t.Cost
' --- [重要] ステップ3: 結果を「値」として書き込む ---
' Number1フィールドに、計算済みの数値だけを代入
' これにより、Number1自体は「数式」ではなく「ただの数字」になります
t.Number1 = baseCost * riskFactor
End If
Next t
' --- [重要] ステップ4: 計算モードを「自動」に戻し、一括再計算 ---
Application.Calculation = pjAutomatic
Application.Calculate
MsgBox "計算完了!" & vbCrLf & _
"処理時間: " & Round(Timer - startTime, 2) & " 秒", vbInformation, "エンジニアの成果"
Exit Sub
ErrorHandler:
' エラーが起きても、計算モードを自動に戻さないとProjectが操作不能になるため必須
Application.Calculation = pjAutomatic
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
4. ここがエンジニアの腕の見せ所(解説)
このコードには、プロとして押さえておくべき3つのエッセンスが詰まっています。
① `Application.Calculation = pjManual` の魔力
これこそが最適化の鍵です。大規模プロジェクトにおいて、ループの中で一つタスクを更新するたびにMS Projectが「再計算」を走らせていたら、終わりが見えません。まず「黙らせる」こと。これが制御の第一歩です。
② 「数式」ではなく「計算結果」を流し込む
カスタムフィールドのプロパティに `[Cost]*[Text1]` と書いておくと、Projectは常に監視を続けます。しかし、VBAで `t.Number1 = 計算結果` と書いてしまえば、そのフィールドはただの「数字」です。監視する必要がなくなるため、動作が圧倒的に軽くなります。
③ エラーハンドリングの重要性
ここを忘れると、マクロがエラーで止まった瞬間、MS Projectが「手動計算モード」のまま固まってしまいます。 「数値を入力しても、スケジュールが全く動かない!」というパニックを防ぐために、`ErrorHandler` で必ず `pjAutomatic` に戻す処理を入れておきましょう。これは現場での「作法」です。
まとめ: 次のステージへ
いかがでしたか?
「マクロの記録」で得たコードは、いわば「操作の録画」です。それに対し、今回学んだ手法は「システムの構造を理解した上での制御」です。
1. 自動計算を止める
2. メモリ上で計算する
3. 結果を値として書き込む
4. 自動計算を再開する
このフローをマスターすれば、あなたはもう「重いプロジェクト」に怯えることはありません。
「なぜ動くのか」だけでなく、「どうすればもっと効率的に動くのか」。その視点を持つことが、伝説のエンジニアへの最短ルートです。
さあ、あなたのプロジェクトを、光のような速さで動かしてみましょう!応援していますよ。
