【テクニカル・上級編】Project VBAによるリソースの「割り当て開始日」の自動調整アルゴリズム – Project VBA解析バイブル

スポンサーリンク

Project VBAの深淵:リソース割り当ての「自動補正」を極めるアーキテクチャ

MS ProjectのVBA(PJOM)を触り始めたエンジニアの多くは、`Assignment.Start`を直接書き換えれば済むという幻想を抱く。しかし、実務レベルの複雑なプロジェクトでそれをやれば、スケジュールは崩壊し、計算エンジンとの終わりのない泥仕合が始まるだけだ。

真のエンジニアは、APIを叩く前に「スケジューリングの整合性」という物理法則を理解している。今回は、タスクの依存関係とリソースの稼働率を考慮し、Assignmentの開始日を最適化するアルゴリズムの核心を伝授する。

—

1. 禁断の領域:なぜ Assignment.Start を直接いじるのが「悪」なのか

MS Projectの計算エンジンは、タスクの `ConstraintType` とリソースカレンダー、そして依存関係(Predecessors)を常に監視している。VBAで `Assignment.Start` を力任せに強制上書きすると、Projectは「ユーザーによる手動オーバーライド」と判定し、それ以降の自動計算を部分的にロックする。

極限の知見:
真に制御すべきは `Assignment` ではなく、親タスクの `Start` と、リソースの `ResourceCalendar` を横断する「空き状況検索アルゴリズム」だ。

2. 実装:リソース空き状況追跡エンジン

以下は、タスクの制約を崩さずに、リソースが空いている最短の日付を特定し、割り当てを行うためのロジックだ。メモリリークを防ぐため、オブジェクト参照の管理には最大限の注意を払っている。

‘ @description リソースの稼働状況を計算し、最短の開始可能日を算出する
‘ @param targetTask 割り当て対象のTaskオブジェクト
‘ @param targetRes 割り当て対象のResourceオブジェクト
Public Sub SmartAssignResource(ByRef targetTask As Object, ByRef targetRes As Object)
Dim pj As Project
Set pj = ActiveProject

‘ 1. メモリ最適化: 参照の明示的利用
‘ オブジェクトをループ内で生成すると、VBAのGCが追いつかないケースがある
Dim resCal As Calendar
Set resCal = targetRes.Calendar

‘ 2. 依存関係の考慮: タスクの最早開始日を取得
Dim earliestStart As Date
earliestStart = GetEarliestPossibleStart(targetTask)

‘ 3. リソース稼働チェック(Windows API / Project API)
‘ カレンダーのWorkingプロパティを検証し、空きスロットを走査する
Dim checkDate As Date
checkDate = earliestStart

Do While Not resCal.Working(checkDate)
checkDate = checkDate + 1
‘ 無限ループ防止用の安全装置(1年先まで)
If checkDate > DateAdd(“yyyy”, 1, earliestStart) Then Exit Sub
Loop

‘ 4. 割り当ての実行: Assignmentは新規生成よりも既存の更新を優先する
Dim assn As Assignment
On Error Resume Next
Set assn = targetTask.Assignments.Add(targetRes.UniqueID)
On Error GoTo 0

If Not assn Is Nothing Then
assn.Start = checkDate
End If

‘ 5. 明示的解放
Set resCal = Nothing
Set assn = Nothing
End Sub

3. パフォーマンスを極めるためのメモリ管理

VBAにおける最大の敵は、`Project` オブジェクトの肥大化によるメモリリークだ。特に数千行のタスクをループ処理する際、`.Assignments` へのアクセスを繰り返すと、Projectの内部キャッシュが飽和する。

  • 参照のキャッシュ: `ActiveProject` や `Task.Assignments` をループの外で変数に格納すること。
  • イベントの無効化: `Application.Calculation = pjManual` を一時的に設定し、処理中の再計算負荷を極限まで下げる。
  • Windows APIの利用: もし外部システム(SAPやkintone等)との連携を行う場合、`WinHttp.WinHttpRequest.5.1` を使用し、非同期通信でリソース情報をキャッシュすることで、ProjectのUIフリーズを回避できる。

4. レガシー環境における保守の鉄則

古いバージョンのProject Serverと連携する場合、`Assignment` の `UniqueID` が環境間で不整合を起こすことがある。

  • GUIDの活用: `Task.Guid` をキーにして、システム間連携の整合性を担保せよ。`UniqueID` はファイルを開き直すだけで変化する可能性がある「脆弱なID」であることを忘れてはならない。
  • トランザクションの意識: 書き込み処理を行う際は、必ず `Application.UndoClear` を呼び出し、変更履歴を適宜管理すること。大規模な修正を行う場合は、処理前に一時的に別名保存させる「スナップショット・バックアップ」をコードに組み込むのがプロの流儀だ。

—

最後に:チーフアーキテクトからの助言

「自動化」とは、単にコードを書くことではない。Projectの計算エンジンという「巨大な黒箱」の挙動を読み解き、その制約の中でいかにエレガントに解を導き出すかという、一種のパズルだ。

君たちが書くその数行のコードが、数百人のプロジェクトメンバーの未来を左右する。パフォーマンスと正確さ、そしてメンテナンス性に妥協するな。このコードは、君が現場を去った後も、誰かの仕事を支える礎となるのだから。

健闘を祈る。

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