【極限の知見】Project VBAを「自己修復」させる。壊れたカスタムフィールドを自動検知し、論理を再構築するアーキテクチャ
こんにちは。現場の最前線で、複雑怪奇なプロジェクト管理の自動化と戦い続けているチーフアーキテクトです。
皆さんは、MS Projectを使っていて、こんな経験はありませんか?
「昨日まで完璧に動いていたカスタムフィールドの計算結果が、なぜか突然 `#ERROR` になった」
「数式を書き換えたはずなのに、なぜか古い計算式が残っている」
「プロジェクトファイルを誰かに渡したら、カスタムフィールドの定義が消えていた……」
これらは、プロジェクト管理における「データの整合性」が崩壊した瞬間です。
特に、数千タスクに及ぶ大規模なプロジェクトでは、一つの数式エラーがプロジェクト全体の意思決定を狂わせる致命的なリスクになります。
今日は、マクロの記録という「初心者向けの階段」を卒業し、「システムが自ら間違いに気づき、自らを治癒する」という、プロフェッショナルな自動化の領域へ皆さまをご案内します。
1. なぜ「マクロの記録」ではカスタムフィールドを制御できないのか
まず、ここで一度立ち止まって考えてみましょう。なぜ、初心者が陥りやすい「マクロの記録」では、カスタムフィールドのメンテナンスに太刀打ちできないのでしょうか。
マクロの記録が生成するのは、いわば「ユーザーの操作の軌跡」です。
「このボタンを押した」「このセルを選択した」という操作は記録できますが、「なぜその数式が必要なのか?」「その数式が正しい状態にあるか?」という「論理(ロジック)」は記録できません。
カスタムフィールドの定義(`CustomField` オブジェクト)は、Projectの内部構造において非常に繊細な場所にあります。
- オブジェクトのライフサイクル(プロジェクトを開いた瞬間、タスクが追加された瞬間)
- 計算エンジンへの負荷
- 数式文字列の構文エラー
これらを考慮せずに「記録」したコードは、環境が変わった瞬間に脆くも崩れ去ります。私たちが目指すのは、操作をなぞるコードではなく、「定義を管理するコード」なのです。
2. 自己修復ツールの設計思想:Golden Standard(黄金律)
壊れたものを直すには、「何が正しい状態か」を知らなければなりません。
今回構築する「自己修復ツール」の核となる概念は、Golden Standard(黄金律)です。
1. 定義の集約: 正しい数式をコード内の「マスターデータ」として保持する。
2. 検知(Detection): 現在のプロジェクトのカスタムフィールドの数式と、マスターデータを照合する。
3. 修復(Repair): 不一致(=エラーまたは改ざん)を発見した場合、即座に正しい数式を上書きする。
このプロセスを自動化することで、人間が手動で「数式が正しいか」をチェックするコストをゼロにします。
3. 実装:Custom Field Self-Healing Engine
それでは、実際に魂を込めて書き上げた、堅牢なVBAコードを見ていきましょう。
このコードは、タスク用のカスタムフィールドをスキャンし、定義が壊れている、あるいは意図しない数式に変更されている場合に、自動的に修正を行います。
Option Explicit
' ==============================================================================
' Module: CustomFieldSelfHealer
' Description: カスタムフィールドの数式を監視し、不一致があれば自動修復する
' Author: Legendary Chief Architect
' ==============================================================================
' カスタムフィールドの定義を管理するための構造体
Private Type FieldDefinition
ID As Integer ' フィールド番号 (1-30)
Name As String ' フィールド名 (例: "重要度スコア")
Formula As String ' 正しい数式
IsTaskField As Boolean ' タスク用かリソース用か
End Type
Sub RunSelfHealingProcess()
Dim masterDefinitions() As FieldDefinition
Dim i As Integer
' 1. 【定義フェーズ】「黄金律(Golden Standard)」を定義する
' ここに、プロジェクトにおける「正しい姿」をすべて書き込みます。
ReDim masterDefinitions(1 To 2) ' 今回は例として2つ定義
' 定義1: タスク用カスタムフィールド
masterDefinitions(1).ID = 1
masterDefinitions(1).Name = "コストリスク係数"
masterDefinitions(1).Formula = "([Cost]*0.1) + [Duration]/10"
masterDefinitions(1).IsTaskField = True
' 定義2: リソース用カスタムフィールド
masterDefinitions(2).ID = 1
masterDefinitions(2).Name = "稼働効率"
masterDefinitions(2).Formula = "[Work]/[Duration]"
masterDefinitions(2).IsTaskField = False
Debug.Print "--- 自己修復プロセス開始 ---"
' 2. 【検知・修復フェーズ】
On Error GoTo ErrorHandler
' 高速化のための設定
Application.ScreenUpdating = False
For i = LBound(masterDefinitions) To UBound(masterDefinitions)
If masterDefinitions(i).IsTaskField Then
RepairTaskField masterDefinitions(i)
Else
RepairResourceField masterDefinitions(i)
End If
Next i
Application.ScreenUpdating = True
Debug.Print "--- 自己修復プロセス完了 ---"
MsgBox "カスタムフィールドの整合性チェックが完了しました。", vbInformation
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
End Sub
''' <summary>
''' タスク用カスタムフィールドを修復する内部関数
''' </summary>
Private Sub RepairTaskField(ByRef def As FieldDefinition)
Dim tf As TaskCustomField
Dim currentFormula As String
' 指定されたIDのカスタムフィールドを取得
' ※Projectのインデックスは1から始まります
Set tf = ActiveProject.TaskCustomFields(def.ID)
currentFormula = tf.Formula
' 【検知ロジック】数式が一致しない、または空の場合に修復を実行
If currentFormula <> def.Formula Then
Debug.Print "[検知] タスクフィールド '" & def.Name & "' の不一致を確認。"
Debug.Print " - 現在の数式: " & currentFormula
Debug.Print " - 期待する数式: " & def.Formula
' 【修復ロジック】
tf.Formula = def.Formula
Debug.Print " => [修復] 正しい数式を再設定しました。"
Else
Debug.Print "[正常] タスクフィールド '" & def.Name & "' は健全です。"
End If
End Sub
''' <summary>
''' リソース用カスタムフィールドを修復する内部関数
''' </summary>
Private Sub RepairResourceField(ByRef def As FieldDefinition)
Dim rf As ResourceCustomField
Dim currentFormula As String
Set rf = ActiveProject.ResourceCustomFields(def.ID)
currentFormula = rf.Formula
If currentFormula <> def.Formula Then
Debug.Print "[検知] リソースフィールド '" & def.Name & "' の不一致を確認。"
rf.Formula = def.Formula
Debug.Print " => [修復] 正しい数式を再設定しました。"
Else
Debug.Print "[正常] リソースフィールド '" & def.Name & "' は健全です。"
End If
End Sub
4. アーキテクトの視点:ここが「プロ」の分かれ目
このコードを単なる「動くコード」で終わらせてはいけません。エンジニアとして、以下の3つのポイントを理解してください。
① オブジェクトモデルへの敬意
コード内で `ActiveProject.TaskCustomFields(def.ID)` を使用しています。これは、UI上の見た目ではなく、Projectの内部データ構造(オブジェクトモデル)に直接アクセスしていることを意味します。これにより、ユーザーがどんなに画面上で操作しても、プログラムは「真実のデータ」を掴み取ることができます。
② パフォーマンスの重み
大規模プロジェクトでは、カスタムフィールドの再計算は非常に重い処理です。
`Application.ScreenUpdating = False` を入れているのは、画面更新を止めることで処理速度を上げると同時に、修復中の画面のチラつきを防ぎ、ユーザーに「今、裏で重要なメンテナンスが行われている」という心理的なストレスを与えないためです。
③ 堅牢なエラーハンドリング
`On Error GoTo ErrorHandler` は、単にエラーを無視するためではなく、「エラーが起きたときに、システムを安全な状態(ScreenUpdatingをTrueに戻すなど)に復帰させるため」に存在します。これこそが、プロフェッショナルなツールに求められる「責任感」です。
5. 次のステップへ
おめでとうございます。あなたは今、「ツールを作る人」から「システムを設計する人」へと一歩踏み出しました。
この自己修復スクリプトは、あくまで基礎です。ここからさらに発展させるなら、以下のような拡張を検討してみてください。
- ログ出力機能: どのフィールドが、いつ、誰によって(あるいは何によって)書き換えられたのかをテキストファイルに記録する。
- 外部定義ファイルとの連携: 数式をVBA内に書くのではなく、ExcelやJSONファイルから読み込むようにし、コードを書き換えずに定義を変更できるようにする。
「動けばいい」という考えを捨て、「壊れない仕組みをどう作るか」を考える。
その思考の積み重ねが、あなたを伝説的なエンジニアへと押し上げるのです。
ここをクリアすれば、Project VBAの基本はバッチリですよ。
さあ、自信を持って、より複雑な課題に挑戦していきましょう!
