意志なきタスクは負債である:Project VBAによる「依存理由の監査ログ」自動化の実装
プロジェクトマネジメントにおいて、WBSの依存関係(Predecessors)は単なる線ではない。それは「なぜこの順序でなければならないのか」という、意思決定の履歴そのものだ。
しかし、Projectの標準フィールドだけでは、この「なぜ」を記録できない。結果、数ヶ月後のレビューで「なぜこのタスクがブロックされているのか」を誰も説明できなくなり、レガシーな運用が泥沼化する。
今回は、Project VBAの深淵に触れつつ、タスクの依存関係に「理由」を付与し、カスタムフィールドへ自動的に監査ログを刻み込むアーキテクチャを提示する。
—
1. アーキテクチャの要諦:なぜ「カスタムフィールド」なのか
Projectの依存関係は `TaskDependencies` コレクションとして管理されるが、これには「理由」を保持するメタデータ領域が存在しない。
解決策は明確だ。
1. Text(カスタムフィールド)の利用: 任意のTextフィールド(例: `Text1`)を監査ログ用として定義する。
2. イベントドリブン・フック: `Project_TaskChange` イベントをフックし、依存関係が変更された瞬間にスタックトレースを記録する。
3. メモリの最適化: 巨大なプロジェクトファイルにおいて、COMオブジェクトの保持は自殺行為である。`Nothing` による解放と、スコープの厳密な管理が不可欠だ。
—
2. 実装:依存関係監査ログの自動追記エンジン
以下のコードは、タスクの依存関係が更新された際、その理由(あるいは変更者とタイムスタンプ)を `Text1` に追記する実用的なモジュールである。
‘ — Class: clsProjectMonitor —
‘ Projectのイベントをキャプチャし、依存関係の変更を監査する
Private Sub Project_TaskChange(ByVal tsk As Task, ByVal Field As PjField)
‘ 依存関係(Predecessors)が変更された場合のみトリガーする
If Field = pjTaskPredecessors Then
Call AuditDependencyChange(tsk)
End If
End Sub
Private Sub AuditDependencyChange(ByRef tsk As Task)
Dim strLog As String
Dim oldLog As String
‘ メモリ最適化: オブジェクトへの参照は最小限のスコープで
On Error Resume Next
oldLog = tsk.Text1
On Error GoTo 0
‘ 監査ログの生成(タイムスタンプ + ユーザー情報 + 依存先ID)
strLog = “[” & Now & “] Dependency Updated: ” & tsk.Predecessors & vbCrLf & _
“Reason: Manually Adjusted by ” & Application.UserName & vbCrLf & _
“—” & vbCrLf & oldLog
‘ 文字数制限の考慮: Text1は255文字制限があるため切り詰め処理を推奨
If Len(strLog) > 250 Then strLog = Left(strLog, 250)
tsk.Text1 = strLog
‘ 明示的なオブジェクト解放はVBAにおいて必須の作法
‘ 参照の循環を防ぐため、サブプロシージャ終了時にクリーンアップ
End Sub
—
3. レガシー環境を生き抜くための極限の知見
Windows APIによるログの永続化
もし監査ログが非常に重要で、Projectファイルの破損リスクを避ける必要がある場合は、VBAから `Kernel32.dll` の `WritePrivateProfileString` を呼び出し、外部のINIファイルやローカルのログサーバーへ書き出す設計に変更すべきだ。
‘ Win32 API宣言
Private Declare PtrSafe Function WritePrivateProfileString Lib “kernel32” Alias “WritePrivateProfileStringA” _
(ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
パフォーマンスを殺さないための「遅延実行」
巨大なプロジェクトで `TaskChange` を多用すると、GUIがフリーズする。`Application.OnTime` を利用してログ書き込みを非同期化するか、あるいはフラグ管理によって「操作終了後の一括書き込み」を行うのが、シニアエンジニアの嗜みである。
—
4. 最後に:システムは「動く」だけでは不十分だ
この運用ツールを導入する最大の目的は、ログを溜めることではない。「後から見た時に、そのタスクの制約条件が論理的に証明されている状態」を作ることだ。
Project VBAは古い言語だが、その背後にあるCOMアーキテクチャを理解していれば、現代的なDevOpsのパイプラインの一部として十分に機能する。
システム管理者諸君、コードを書く前にまず「なぜ依存するのか」というプロセスの設計を磨いてほしい。技術は目的のための手段に過ぎない。しかし、その手段が極限まで洗練されている時、プロジェクトの成功率は劇的に向上する。
—
文責:Project VBAチーフアーキテクト
