【実務・中級編】【実務中級】Taskの「Text1〜30」フィールドを活用した外部システムとのデータマッピング戦略 – Project VBA解析バイブル

スポンサーリンク

【実務中級】MS Projectの生命線:`Text1〜30`を用いた外部システム連携の極限設計と実装

開発プロジェクトの現場において、Microsoft Project(以下、MSP)を単なる「ガントチャートのお絵描きツール」として扱っているうちは、ツール本来の価値を引き出せているとは言えない。

真にアジャイルかつ強靭なPMO組織では、MSPは「プロジェクトの全容を制御するマスターデータベース」として機能する。そして、その中核をなすのが、タスクオブジェクトに用意された30個のカスタムテキストフィールド、`Text1` から `Text30` である。

今回は、外部システム(ERP、Jira、独自進捗管理DBなど)とMSPの間で、データの整合性を1ミリも狂わせずに双方向同期させるためのデータマッピング戦略と、その実践コードを伝授する。

なぜ「力技の同期」は破綻するのか?(アンチパターンと現実)

外部システムとの連携を考えたとき、素人が真っ先に思いつくのが以下の実装だ。

  • 「タスク名」をキーにして突合する
  • 現実: 現場のエンジニアは平気でタスク名を書き換える。「要件定義」が「要件定義(修正版)」になった瞬間、外部キーとしての機能は完全に死滅する。
  • 毎回全件削除してインポートし直す
  • 現実: MSPのオブジェクトモデルの重みを知らない者の悪夢。`Task`コレクションを全走査して削除・再作成すると、アサインされているリソース情報や実績工数(Actual Work)の履歴、ベースラインがすべて吹き飛ぶ。

プロジェクトの鉄則:MSPの内部IDとカスタムフィールドの二重防衛

外部システムとのマッピングにおいて、信頼できるキーは以下の2つしかない。

1. `UniqueID`(読み取り専用): MSPが自動採番する不変のID。ただし外部システム側でこれを保持・コントロールするのは困難。
2. `Textフィールド`(書き込み可能): 外部システムの主キー(UUIDやチケットIDなど)を格納する「外字領域」。

この `Text1` を外部システム連携用のパーマネントキー(Guid)として予約し、他の用途での流用を厳禁とすること。これが堅牢なインテグレーションの第一歩である。

アーキテクチャ設計:マッピング戦略の全体像

外部システムからJSONやCSVを受け取り、MSPへ流し込む(あるいはその逆)際の流れを定義する。

[外部DB / API]
↕ (JSON / CSV)
[VBA マッパーエンジン]
↕ (Find / Match)
[MSP Task.Text1 (External ID)] ⇄ [Task.Name / Start / Finish / etc.]

1. 検索の最適化(全件走査の排除)

`For Each t In ActiveProject.Tasks` を毎回回すようなコードは、タスク数が数千件を超えた時点で実用に耐えない(COMのオーバーヘッドで数分かかる)。
MSPのVBAにはSQLのようなリレーショナルな検索機能はないが、「カスタムフィールドの値で一発特定するラッパー関数」を自作することで、パフォーマンスを劇的に改善できる。

実践プロダクションコード:堅牢な同期モジュール

以下のコードは、外部システムから受け取ったデータを想定し、`Text1`(外部ID)をキーにして、既存タスクがあれば「更新」、なければ「新規作成」を行うロジックである。

エラーハンドリング、トランザクション的な視点、そしてCOMのメモリ解放まで考慮した、プロダクション品質のコードを提示する。

Option Explicit

‘ =========================================================================
‘ モジュール名: mSyncEngine
‘ 概要: 外部システムとMSPのTaskオブジェクトをText1(外部ID)で同期する
‘ =========================================================================

Public Sub SynchronizeTaskFromExternal(ByVal externalId As String, _
ByVal taskName As String, _
ByVal targetStart As Date, _
ByVal targetFinish As Date)
On Error GoTo ErrorHandler

Dim targetTask As Task
Set targetTask = FindTaskByExternalId(externalId)

‘ アプリケーションのパフォーマンス向上(画面描画・自動計算の抑制)
Application.ScreenUpdating False

If targetTask Is Nothing Then
‘ — 新規作成フェーズ —
Set targetTask = ActiveProject.Tasks.Add(taskName)

‘ 外部IDをText1に焼き付ける(以降のライフサイクルの主キーとなる)
targetTask.Text1 = externalId

Debug.Print “新規タスク作成: ID[” & externalId & “] ” & taskName
Else
‘ — 更新フェーズ —
‘ 変更が必要な項目のみアップデート
If targetTask.Name <> taskName Then targetTask.Name = taskName
If targetTask.Start <> targetStart Then targetTask.Start = targetStart
If targetTask.Finish <> targetFinish Then targetTask.Finish = targetFinish

Debug.Print “タスク更新: ID[” & externalId & “] ” & taskName
End If

CleanUp:
Application.ScreenUpdating True
Exit Sub

ErrorHandler:
MsgBox “同期処理中に致命的なエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“詳細: ” & Err.Description, vbCritical, “MSP同期エンジン”
Resume CleanUp
End Sub

‘ =========================================================================
‘ 補助関数: Text1の値からTaskオブジェクトをO(N)で高速検索する
‘ ※大規模プロジェクトではDictionary等へのキャッシュ併用を推奨
‘ =========================================================================
Private Function FindTaskByExternalId(ByVal externalId As String) As Task
Dim t As Task
Dim found As Task
Set found = Nothing

For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ Text1が一致するか判定
If t.Text1 = externalId Then
Set found = t
Exit For
End If
End If
Next t

Set FindTaskByExternalId = found
End Function

運用・保守における極意と注意点

この設計を現場に導入するにあたり、以下の「現場の罠」に注意せよ。

1. ユーザーによる `Text1` の手動上書きを防ぐ

`Text1` は画面上に表示させておくと、現場のユーザーが誤って値を消したり書き換えたりする事故が必ず起きる。

  • 対策: 運用時は `Text1` 列を非表示(または読み取り専用ビューの強制)にするか、`TaskBeforeEdit` イベントなどをフックして、外部ID領域の不正な手動変更を検知・ロールバックする仕組みを入れる。

2. データ型の不一致とパディング

外部システム側で文字列として扱われているID(例: `”00123″`)が、VBAの暗黙の型変換やExcel経由のインポート時に数値として解釈され、先頭の `0` が落ちて `”123″` になる現象が多発する。

  • 対策: `Text` フィールドに格納する値は、必ず文字列型(String)として厳格に扱い、比較時も `CStr()` 等で型を担保すること。

3. 大規模データ処理時のパフォーマンスチューニング

タスク数が5,000件を超える場合、毎回 `For Each` で `Text1` を線形探索するのは非効率である。
もし一括同期(バルクインポート)を行う場合は、処理の最初に一度すべてのタスクの `UniqueID` と `Text1` のマッピングを Scripting.Dictionary に読み込み、メモリ上で高速にヒット判定を行うアーキテクチャにブラッシュアップせよ。

結言:ツールに振り回されるな、ツールを従えろ

MSPのカスタムフィールド (`Text1〜30`) は、いわば開発者へ与えられた「拡張スロット」だ。これを適当なメモ書きに使うか、外部システムとの堅牢な結合キーとして体系化するかで、ツールとしての寿命は天と地ほど変わる。

「なぜこのキーが必要なのか」「どうすればシステム間の整合性を担保できるのか」。
その設計思想さえブレなければ、VBAは単なるマクロの域を脱し、組織の生産性を担保する強固なインフラストラクチャへと昇華する。現場のエンジニアよ、今すぐコードを書き換え、真の自動化をその手に掴み取れ。

タイトルとURLをコピーしました