凡庸な「リソース管理」を捨て去れ:Project VBAにおけるスキル検索エンジンの深淵
多くのエンジニアがProject VBAの「Resource.Textフィールド」をただのメモ帳として扱っている。それは、フェラーリのエンジンをドアストッパーに使っているようなものだ。
大規模なプロジェクトにおいて、リソースの適材適所は単なる管理課題ではない。それは「プロジェクトの生存戦略」そのものだ。本稿では、レガシーなProject VBAの制約を逆手に取り、メモリを極限まで絞り込み、高速なスキルマッチングエンジンを構築するためのアーキテクチャを提示する。
—
1. なぜ「標準機能」では足りないのか
Projectの標準的なリソース検索は、単一の属性値マッチングに終始する。しかし、現実のプロジェクトにおいてスキルは「複合的」だ。
- スキルコード管理: `VBA.Collection`や`Scripting.Dictionary`を用いたメモリ上でのインデックス構築。
- 探索アルゴリズム: 単純ループによる`Resource.Text`の走査は、リソースが数百名を超えた瞬間に破綻する。
我々は、リソースを「オブジェクト」としてではなく「データセットの集合体」として扱い、バイナリに近い速度で探索を行う必要がある。
2. 高速化の要:スキル・インデックス・エンジン
`Resource.Text`を解析する際、毎回`InStr`を繰り返すのは愚の骨頂だ。初回ロード時にすべてのスキルをハッシュマップに展開せよ。
‘ スキルを管理するクラスモジュール: CSkillIndex
Option Explicit
Private pMap As Object ‘ Scripting.Dictionary
Private Sub Class_Initialize()
Set pMap = CreateObject(“Scripting.Dictionary”)
End Sub
‘ リソースのテキストを解析してインデックス化
Public Sub BuildIndex(res As Resource)
Dim skills() As String
Dim i As Long
‘ Text1フィールドにカンマ区切りでスキルを格納していると仮定
skills = Split(res.Text1, “,”)
For i = LBound(skills) To UBound(skills)
If Not pMap.Exists(skills(i)) Then
pMap.Add skills(i), New Collection
End If
pMap(skills(i)).Add res.ID
Next i
End Sub
‘ 検索エンジン
Public Function FindResourcesBySkill(skillCode As String) As Collection
If pMap.Exists(skillCode) Then
Set FindResourcesBySkill = pMap(skillCode)
Else
Set FindResourcesBySkill = New Collection
End If
End Function
—
3. メモリの解放:アーキテクトの矜持
VBAにおけるメモリリークは、循環参照と「明示的な解放の怠慢」から生まれる。特にProjectオブジェクトモデルは複雑であり、`Project.Resources`を走査した際、暗黙のオブジェクト参照が残ることがある。
極限の最適化テクニック:
- Set Nothingの徹底: クラスの`Terminate`イベントを信じるな。呼び出し元のスタックで必ず`Set`オブジェクトを破棄せよ。
- Windows APIの活用: 大規模なデータセットを扱う際、VBAのコレクションのメモリ消費が許容できない場合は、`GlobalAlloc`等のWindows APIを用いてヒープメモリを直接操作する手法も検討すべきだ。ただし、これはVBAの安全装置を外す行為である。
‘ 厳格なクリーンアップ・ルーチン
Public Sub ShutdownEngine(ByRef target As CSkillIndex)
‘ 内部のDictionaryを空にし、参照カウントを強制的に下げる
Set target = Nothing
‘ ガベージコレクションを強制的に働かせることはできないが、
‘ 参照を断ち切ることでメモリ解放の機会を最大化する
End Sub
—
4. システム間連携の最適化:CSVか、直接参照か
もし貴殿が外部のスキルDB(SQL Server等)と連携しているなら、VBAだけで完結させようとしてはならない。
1. ADO(ActiveX Data Objects)の非同期読み込み: `ADODB.Recordset`を用いてデータを取得し、それを`Variant`配列に格納せよ。`Range`や`Resource`オブジェクトを逐一操作するのは遅延の元凶だ。
2. バイナリ・ストリームの活用: `ADODB.Stream`を用いて、スキルコードのマスターデータをローカルのバイナリキャッシュとして保存し、起動時に一気にメモリへ展開する。これにより、サーバーへの問い合わせ回数を最小化できる。
—
5. 最後に:レガシーを飼いならすということ
Project VBAは古い言語だが、その背後にあるオブジェクトモデルは極めて強力だ。
「動けばいい」というコードと、「計算量を理解し、メモリを管理し、拡張性を担保した」コードの間には、エンジニアとしての格差がある。
リソース検索エンジンを構築する際は、常に「このシステムが1万リソースを超えたとき、どう振る舞うか?」を自問せよ。その問いに対する答えが、貴殿のアーキテクチャの強度となる。
コードは嘘をつかない。貴殿の書いた一行一行が、プロジェクトの未来を左右する。健闘を祈る。
