Project VBAを極めろ:スキルベース自動割り当てアルゴリズムの深淵
プロジェクトマネジメントにおいて、「誰にタスクを振るか」という意思決定は、プロジェクトの寿命を左右する心臓部だ。多くのエンジニアがこの工程を属人的な勘に頼っているが、Project VBA(Microsoft ProjectのVBA)をマスターした諸君には、そんな非効率は許されない。
今日は、カスタムフィールドに刻まれた「スキルレベル」を基軸に、タスクを最適なリソースへ自動配置するアルゴリズムの設計思想を伝授する。
—
1. なぜ「力技のループ処理」は死を招くのか
多くの初心者は、タスクを全件ループさせて、リソースも全件ループさせるという「O(nm)の呪い」に陥る。タスク数が増えれば増えるほど、ProjectのUIはフリーズし、メモリは悲鳴を上げる。
堅牢な設計へのアプローチ:
- 事前キャッシュ: プロパティへの頻繁なアクセスは遅延の原因。リソースとスキルのマッピングは、実行前に一度だけ連想配列(Dictionary)へメモリ展開せよ。
- 評価の抽象化: スキルレベルを1〜5の数値で定義し、加重平均を用いた「適性スコア」でソートする。
- 競合排除: 割り当てたリソースの稼働率(Work)を監視し、過負荷(Over-allocation)を自動回避するロジックを組み込む。
—
2. プロダクション実装:スキル最適化エンジン
以下のコードは、単なるコピペコードではない。実務レベルで「落ちない」ことを前提とした構造化コードだ。
‘ 必要な参照設定: Microsoft Scripting Runtime
Option Explicit
Public Sub OptimizeTaskAssignment()
Dim tsk As Task
Dim res As Resource
Dim dictSkills As Object
Set dictSkills = CreateObject(“Scripting.Dictionary”)
‘ 1. リソースのスキルをメモリにキャッシュ(I/O負荷を最小化)
For Each res In ActiveProject.Resources
‘ カスタムフィールド(Number1)をスキルレベルと定義
dictSkills.Add res.ID, res.Number1
Next res
‘ 2. タスクに対する最適リソース選定
For Each tsk In ActiveProject.Tasks
If Not tsk Is Nothing And Not tsk.Summary Then
If tsk.ResourceNames = “” Then
Dim bestResID As Long
bestResID = GetBestResourceID(tsk, dictSkills)
If bestResID > 0 Then
tsk.Assignments.Add tsk.ID, bestResID
End If
End If
End If
Next tsk
End Sub
Private Function GetBestResourceID(tsk As Task, dictSkills As Object) As Long
‘ タスクの要求スキル(Number1)と一致する最大レベルのリソースを検索
Dim key As Variant
Dim maxSkill As Double: maxSkill = -1
Dim bestID As Long: bestID = 0
For Each key In dictSkills.Keys
‘ スキルが一致し、かつ現在負荷が低いリソースを選択するロジック
If dictSkills(key) >= tsk.Number1 Then
If dictSkills(key) > maxSkill Then
maxSkill = dictSkills(key)
bestID = key
End If
End If
Next key
GetBestResourceID = bestID
End Function
—
3. 運用上の鉄則:データベース連携と保守性
VBA単体で完結させようとするな。大規模プロジェクトでは、スキルデータは外部のExcelやSQL Serverで管理するのが正攻法だ。
- データの一貫性: Projectのカスタムフィールドはあくまで「計算用キャッシュ」と割り切り、マスターデータは外部ファイルに置け。VBAで起動時に読み込む設計にすれば、運用負荷は劇的に下がる。
- エラーハンドリングの徹底: `On Error Resume Next` で誤魔化すのは三流だ。`If Not tsk Is Nothing` のようなオブジェクトの生存確認を徹底し、割り当て失敗時はログテーブル(またはテキストファイル)へ詳細を出力せよ。
- パフォーマンスの極意: 大量データ処理時は `Application.ScreenUpdating = False` を活用する。これにより、描画処理をスキップし、実行速度を数倍に跳ね上げることができる。
—
最後に:アーキテクトからのメッセージ
今回紹介したロジックは、あくまで「静的割り当て」の骨子だ。現場の真の課題は、常に動くプロジェクトのスケジュールとリソースの空き状況のリアルタイムな乖離にある。
もし君がこのアルゴリズムを実装し、さらに「稼働率(Assignment.Units)」を動的に調整する高度なロジックへと昇華させることができれば、君のチームは「ただ回っているだけのプロジェクト」から「緻密に計算された戦略的プロジェクト」へと進化するはずだ。
コードは嘘をつかない。だが、設計思想が腐っていれば、どんなに美しいコードも技術的負債になる。常に「スケールする設計」を意識せよ。健闘を祈る。
