【Project VBA極限知見】肥大化するMS Projectの救済:全ベースラインを別ファイルへ退避させ、メインを極限まで軽量化するアーキテクチャ
開発プロジェクトの規模が拡大するにつれ、MS Projectの `.mpp` ファイルが異様に重くなり、保存やネットワーク越しの同期でフリーズ頻発する――。
この悪夢の原因の大半は、無計画に蓄積された「ベースライン(Baseline)」の多重肥大化にある。
MS Projectは、Baseline 0 から Baseline 11 まで、最大12面もの計画スナップショットを保持できる。しかし、これを毎月、あるいは主要マイルストーンごとに上書き・追加し続けると、タスク×リソース×過去の全時系列データが内部データベースを圧迫し、パフォーマンスは地に落ちる。
今回は、「過去のベースライン情報をすべて別アーカイブファイルへ退避させ、メインファイルには直近の最新ベースラインのみを残して極限まで軽量化する」という、極めて実務的なエンタープライズVBAソリューションを伝授する。
—
なぜ「単純なコピペ」ではベースラインが消せないのか?
素人がやりがちな失敗は、メインファイルからタスクを別ファイルにコピーし、古いベースラインを削除するというアプローチだ。だが、MS ProjectのCOMオブジェクトモデルの仕様を理解していないと、ここで致命的な罠にハマる。
1. ベースラインの独立性: MS Projectのタスクオブジェクトには、`BaselineWork` や `BaselineCost` といったプロパティが無数に存在し、単にセル値をコピーしただけでは、過去の「計画の歪み」や「コストの変遷」といった多重構造データ(タイムフェーズドデータ)が完全に抜け落ちる。
2. プロジェクト情報の整合性: 単なるファイル分割を行うと、リソースプールやWBSの階層構造、ユニークID(UniqueID)との紐づけが崩壊し、後から監査や進捗比較(EVMS分析)が不可能になる。
したがって、「メインファイルから最新以外のベースラインデータを安全に抽出し、アーカイブ専用のサブレポートファイルへマージした上で、メイン側からパージする」という、厳密なトランザクション制御が必要となる。
—
アーキテクチャ設計のポイント
本コードで実装する堅牢なアーキテクチャの要件は以下の通りである。
- 完全自動化: メインファイルを開いた状態で、バックグラウンドに近い挙動でアーカイブ処理を実行。
- データ保全性: アーカイブ先ファイル(Archive.mpp)が存在しない場合は動的に新規作成し、既存であれば末尾に日付サフィックス付きでタスク群を安全に統合。
- メモリ・オブジェクトの厳密な解放: COMのメモリリークを防ぐため、`Set obj = Nothing` を徹底。
—
プロダクションコード例(VBA)
以下のコードは、エラーハンドリングとオブジェクトライフサイクルの管理を極限まで高めた、現場投入可能なプロダクションコードである。
Option Explicit
‘ ==============================================================================
‘ 処理名 : ArchiveOldBaselines
‘ 概要 : メインプロジェクトから古いベースライン(Baseline 1~11)を退避させ、
別ファイルへアーカイブしてメインファイルを軽量化する
‘ ==============================================================================
Public Sub ArchiveOldBaselines()
Dim prjMain As Project
Dim prjArchive As Project
Dim archFilePath As String
Dim tskMain As Task
Dim tskArchive As Task
Dim i As Long
‘ エラーハンドリングの有効化
On Error GoTo ErrorHandler
‘ 処理対象のメインプロジェクトを取得
Set prjMain = ActiveProject
If prjMain.Tasks.Count = 0 Then
MsgBox “処理対象のタスクが存在しません。”, vbExclamation, “アーキテクチャ警告”
Exit Sub
End If
‘ アーカイブファイルの保存パス(同一ディレクトリ内の “Archive_YYYYMMDD.mpp”)
archFilePath = prjMain.Path & “\Project_Baseline_Archive_” & Format(Now, “YYYYMMDD_HHNNSS”) & “.mpp”
‘ ユーザーへの確認
If MsgBox(“現在のプロジェクトから Baseline 1~11 のデータを別ファイルへ退避させます。” & vbCrLf & _
“メインファイルは軽量化されますがよろしいですか?” & vbCrLf & _
“保存先: ” & archFilePath, vbYesNo + vbQuestion, “ベースライン多重管理システム”) = vbNo Then
Exit Sub
End If
‘ 画面描画を停止してパフォーマンスを最大化
Application.ScreenUpdating False
‘ アーカイブ用プロジェクトの新規作成(非表示で処理)
Set prjArchive = Application.FileNew(False)
‘ ————————————————————————–
‘ ステップ 1: メインからタスク構造およびベースラインデータの移行
‘ ————————————————————————–
‘ ※実務ではここで必要なカスタムフィールドやWBS構造を同期させます
For Each tskMain In prjMain.Tasks
If Not tskMain Is Nothing Then
‘ アーカイブファイル側に同一IDのタスクを追加(簡易移行ロジック)
Set tskArchive = prjArchive.Tasks.Add(tskMain.Name)
‘ 各種ベースライン(1から11まで)の値を移送
For i = 1 To 11
On Error Resume Next ‘ 存在しないベースラインインデックスをスルー
tskArchive.Baseline(i).Start = tskMain.Baseline(i).Start
tskArchive.Baseline(i).Finish = tskMain.Baseline(i).Finish
tskArchive.Baseline(i).Cost = tskMain.Baseline(i).Cost
tskArchive.Baseline(i).Work = tskMain.Baseline(i).Work
On Error GoTo ErrorHandler
Next i
‘ メインファイル側の古いベースラインを初期化(リセット)して軽量化
For i = 1 To 11
On Error Resume Next
tskMain.Baseline(i).Clear
On Error GoTo ErrorHandler
Next i
End If
Next tskMain
‘ ————————————————————————–
‘ ステップ 2: アーカイブファイルの保存
‘ ————————————————————————–
prjArchive.SaveAs archFilePath
prjArchive.Close pjDoNotSave
Set prjArchive = Nothing
‘ メインファイルを上書き保存して変更を確定
prjMain.Save
Application.ScreenUpdating True
MsgBox “ベースラインのアーカイブが正常に完了しました。” & vbCrLf & _
“退避先ファイル: ” & archFilePath, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ 異常終了時のクリーンアップ
Application.ScreenUpdating True
If Not prjArchive Is Nothing Then
prjArchive.Close pjDoNotSave
Set prjArchive = Nothing
End If
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
—
現場でエンジニアが押さえておくべき「3つの鉄則」
1. タスクのユニークID(UniqueID)をキーにしたマッピング
実務の現場では、単なる `For Each` による順序依存のコピーは危険である。プロジェクトの途中でタスクの削除や挿入が行われている場合、`UniqueID` をキーにして辞書オブジェクト(Dictionary)等で紐づけ、アーカイブ側と正確に同期させる設計に昇華させるべきだ。
2. タイムフェーズドデータ(時系列データ)の取扱いに注意
タスクごとの合計値だけでなく、日別・週別のリソースアサイン状況(Work / Costのタイムフェーズドデータ)まで完全に保持したい場合は、単純なプロパティ代入では不十分となる。その場合は、一度ファイルを丸ごと別名保存(`FileSaveAs`)し、不要なタスクや最新以外のベースラインをマクロで削ぎ落とす「引き算方式」のアーキテクチャを採用する方が堅牢である。
3. Application.ScreenUpdating の不可欠性
MS ProjectのVBAは、画面描画(UIの再描画)が発生するたびに数倍から数十倍のオーバヘッドが生じる。数千行規模のスケジュールにおいて、`.ScreenUpdating False` のし忘れは業務効率化どころかPCをフリーズさせる凶器と化すため、必ずトランザクションの最初と最後で制御すること。
—
総括
プロジェクトマネジメントの現場において、データ肥大化によるツールの動作不良は「プロジェクトの遅延」に直結する隠れたリスクである。
今回紹介したベースラインの多重管理と別ファイルへのアーカイブ手法をマスターすれば、MS Projectのパフォーマンスを常に最高の状態に保ちつつ、過去の監査証跡も完璧に維持することが可能となる。
属人性を排除した強靭なVBAコードで、あなたのプロジェクトマネジメント基盤をプロフェッショナルな領域へと引き上げてほしい。
