Project VBAを掌握する極限の知見:ベースラインの多重運用と自動コピーマクロの設計思想
開発プロジェクトの現場において、進捗管理の精度を担保するために「ベースライン」の存在は不可欠だ。しかし、Project VBAを用いた実務の現場では、単に `Baseline` プロパティを叩くだけの安易なコードが蔓延している。
「計画が変更されるたびにベースラインを上書きしてしまい、当初の遅延状況が追えなくなった」
「どのスロットにどの時点の計画が入っているのか判別がつかない」
こうした悲劇は、MS Projectが持つベースライン構造のライフサイクルと、VBAからの適切な操作手順を理解していないことに起因する。
今回は、「現在の計画(直近の修正計画)」と「当初計画(プロジェクト発足時の計画)」を明確に分離・維持し、プロジェクトの信頼性を担保するための堅牢な自動コピーマクロの設計手法を伝授する。
—
1. MS Projectにおけるベースラインの裏側:仕様の罠
MS Projectには、`Baseline`(無印)から `Baseline 10` まで、計11個のスロットが用意されている。多くの開発者が犯す最大のミスは、「最新の計画を常に無印の Baseline に上書き保存してしまうこと」だ。
無印のベースラインを上書きしてしまうと、クライアントやマネジメント層から「最初の計画からどれだけ乖離したのか」を問われた際、正確なデータを提示できなくなる。
堅牢な運用ルール(実務標準)
- Baseline 0(無印): 当初計画(Project Charter承認時のスプレッド。一度設定したら原則ロック)
- Baseline 1: 現在の計画(スコープ変更や大きなリスケジュールが発生した際に更新する直近の計画)
この運用をヒューマンエラーなしで徹底させるためには、VBAによる自動制御ロジックを組み込むのが唯一にして最大の解決策である。
—
2. アーキテクチャ設計:バグを生まないための3つの鉄則
実務で稼働するツールを開発する際、以下の3点は妥協してはならない。
1. 明示的なスロット指定(CopyBaselineメソッドの活用)
MS Projectの標準機能にある「ベースラインの保存」ダイアログに頼らず、VBAの `Application.CopyBaseline` を用いて、どのスロットからどのスロットへデータを転送するかをコード内で完全に制御する。
2. 存在確認とエラーハンドリング
ベースラインが一度も設定されていない状態でコピー元を参照すると、予期せぬランタイムエラーやデータ化けを引き起こす。実行前のガード節(Guard Clause)は必須である。
3. トランザクション的思考
処理の途中で中断された場合に中途半端なデータが残らないよう、処理の前後でビューやアクティブ状態の整合性を保つ。
—
3. プロダクションコード:ベースライン自動管理モジュール
以下のコードは、現場の即戦力としてそのまま組み込めるプロダクション品質のVBAコードだ。
「当初計画(Baseline 0)」が未設定の場合は自動で初期化し、「現在の計画(Baseline 1)」へ最新のスケジュールを退避・更新するロジックを実装している。
‘ ==============================================================================
‘ Module:
‘ 概要: 当初計画と現在計画のベースラインを安全に制御・同期するプロシージャ
‘ アーキテクト: チーフアーキテクト直伝
‘ ==============================================================================
Option Explicit
Public Sub ManageProjectBaselines()
Dim prj As Project
Set prj = ActiveProject
‘ エラーハンドリングの有効化
On Error GoTo ErrorHandler
‘ 処理前の確認ダイアログ(実務での誤操作防止)
Dim userResponse As VbMsgBoxResult
userResponse = MsgBox(“プロジェクトのベースラインを更新します。” & vbCrLf & _
“【Baseline 0】当初計画(未設定の場合のみ初期化)” & vbCrLf & _
“【Baseline 1】現在の計画(最新スケジュールで上書き)” & vbCrLf & _
vbCrLf & “実行してもよろしいですか?”, _
vbYesNo + vbQuestion, “ベースライン管理システム”)
If userResponse = vbNo Then Exit Sub
‘ 1. 当初計画 (Baseline 0) の保護と初期化チェック
‘ MS Projectでは、ベースラインが設定されているかを直接判定するプロパティが弱いため、
‘ スタート日の有無等で擬似的に判定するか、初回のみ手動/自動でセットする設計にする。
‘ ここでは安全のため、Baseline0のサマリータスクのコストや日付が空かチェックするロジックを想定。
Call EnsureBaselineZero(prj)
‘ 2. 現在の計画 (Baseline 1) の更新
‘ 現在のスケジュール(Start / Finish / Cost)を Baseline 1 にコピーする
‘ 引数: FromType, FromCopy, ToType, ToCopy
‘ pjCopyBaseline = 現在の計画をコピー元とする
‘ pjBaseline = 無印(Baseline 0), pjBaseline1 = Baseline 1
Application.CopyBaseline FromType:=pjCopyBaseline, FromCopy:=pjBaseline, _
ToType:=pjBaseline1, ToCopy:=pjBaseline1
MsgBox “ベースラインの更新が完了しました。” & vbCrLf & _
“- 当初計画 (Baseline 0): 保持または初期設定済み” & vbCrLf & _
“- 現在の計画 (Baseline 1): 最新のスケジュールで更新されました”, _
vbInformation, “処理成功”
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, _
vbCritical, “システムエラー”
End Sub
‘ ==============================================================================
‘ 補助プロシージャ: 当初計画(Baseline 0)の未設定時イニカライズ
‘ ==============================================================================
Private Sub EnsureBaselineZero(ByRef targetProject As Project)
Dim tsk As Task
Dim isB0Exists As Boolean
isB0Exists = True
‘ 簡易チェック: 先頭のタスクのBaseline0開始日が設定されているか確認
On Error Resume Next
For Each tsk in targetProject.Tasks
If Not tsk Is Nothing Then
If tsk.BaselineStart = “NA” Or tsk.BaselineStart = #1/1/2000# Then
isB0Exists = False
Exit For
End If
End If
Next tsk
On Error GoTo 0
‘ Baseline 0 が未設定(あるいは初期値)の場合のみ、現在の計画をBaseline 0として保存
If Not isB0Exists Then
targetProject.SetBaseline Baseline:=pjBaseline
MsgBox “当初計画(Baseline 0)が未設定だったため、現在のスケジュールを初期値としてロックしました。”, _
vbInformation, “当初計画 初期化”
End If
End Sub
—
4. 現場で活きる!データベース連携・運用時の注意点
このマクロをチーム全体の共通基盤(グローバルテンプレート `Global.mpt` や、各PJのエンタープライズテンプレート)に組み込む際、以下のインフラ的観点を忘れてはならない。
- PWA (Project Web App) / Project Server 連携時の挙動
オンプレミスやクラウドのProject Server環境でEnterprise Project Management (EPM) を行っている場合、ローカルVBAからの強制的なベースライン上書きは、サーバー側の権限設定やチェックアウト状態に阻まれることがある。サーバー環境へ導入する際は、事前に `ActiveProject.CheckOut` 状態の確認ロジックを挟むこと。
- パフォーマンスへの配慮
数万行に及ぶ大規模工程表において、`For Each` によるタスク走査は若干のオーバーヘッドを生む。もしパフォーマンスがボトルネックになる場合は、タスクの走査を行わず、API側のエラーハンドリングのみで `SetBaseline` を実行するスリムな設計に切り替える判断力もエンジニアには求められる。
総括
ベースラインの多重運用は、プロジェクトの「正史(当初計画)」と「現在地(最新計画)」を視覚化し、ステークホルダーとの折衝を有利に進めるための強力な武器となる。
泥臭い手動運用から脱却し、VBAによる厳格なガバナンスをあなたのプロジェクトにインストールしてほしい。
