こんにちは!日々のプロジェクト管理、本当にお疲れ様です。
「マクロの記録」から一歩踏み出し、自分だけの自動化ツールを作り始めたものの、気づけば何百行もある巨大なプロシージャ(いわゆるスパゲッティコード)になってしまい、どこを直せばいいか分からなくなった……そんな経験はありませんか?
今回は、レガシーなProject VBAコードを「クラスモジュール」を使って美しく構造化し、保守性と再利用性を劇的に向上させるリファクタリングの手法を伝授します。
「クラスモジュールなんて难しそう……」と思うかもしれませんが、大丈夫です。ここをクリアすれば、あなたのVBAスキルは間違いなくワンランク上のステージに到達します。さあ、一緒に本物のエンジニアへの階段を登っていきましょう!
—
1. なぜレガシーなコードはメンテナンス不能になるのか?
「マクロの記録」や、古いVBAのサンプルコードを寄せ集めて作ったプログラムによくある症状がこれです。
- 1つの標準モジュールにすべての処理(タスクの取得、判定、書き込み)が書かれている
- グローバル変数があちこちで書き換えられ、どこで値が変わったのか追えない
- 「ちょっと仕様が変わった(例:特定のリソース名が変わった)」だけで、コード全体を直すハメになる
Project VBAは、Excel VBAとは異なり、「タスク」「リソース」「アサインメント」といった複雑な階層構造(オブジェクトモデル)を相手にします。これをベタ書きのプロシージャで制御しようとすると、すぐにコードが破綻します。
ここで救世主となるのが、オブジェクト指向の基本である「クラスモジュール」です。
—
2. クラスモジュールによるカプセル化の魔法
クラスモジュールとは、いわば「自分専用のカスタムオブジェクト(設計図)」を作る機能です。
例えば、「プロジェクト内の特定条件のタスクを操作する処理」をひとつのクラスに閉じ込めて(カプセル化して)しまいます。呼び出し側(標準モジュール)は、内部がどうなっているかを気にする必要はなく、「このクラスにお願いすれば、いい感じにやってくれる」という状態を作ります。
今回リファクタリングするシナリオ
「指定した期間内に開始するタスクを抽出し、特定のカスタムフィールドにフラグを立てる」というよくある処理を例に取ります。
—
3. 実践!レガシーコードからモダンなクラス設計へのリファクタリング
それでは、具体的なコードを見ていきましょう。まずは準備として、VBE(Visual Basic Editor)のメニューから [挿入] > [クラス モジュール] を選択し、プロパティウィンドウで名前を `TaskProcessor` に変更してください。
ステップ1:クラスモジュール(TaskProcessor.cls)の作成
ここに、タスク操作に関するロジックを閉じ込めます。
‘ =================================フォーマット=================================
‘ クラス名: TaskProcessor
‘ 概要: Project内のタスクを走査し、条件に応じた処理を行うカプセル化クラス
‘ ==============================================================================
Option Explicit
‘ プライベート変数(外部から直接触らせないことで安全性を担保する)
Private m_TargetProject As MSProject.Project
Private m_ThresholdDate As Date
‘ 初期化メソッド(コンストラクタの代わり)
Public Sub Initialize(ByVal targetProj As MSProject.Project, ByVal threshold As Date)
Set m_TargetProject = targetProj
m_ThresholdDate = threshold
End Sub
‘ 実行メソッド:閾値より前に開始するタスクのフラグを立てる
Public Sub ProcessEarlyTasks(ByVal flagFieldName As String)
Dim t As MSProject.Task
‘ エラーハンドリングの基本
On Error GoTo ErrorHandler
If m_TargetProject Is Nothing Then
MsgBox “プロジェクトが設定されていません。”, vbCritical
Exit Sub
}
‘ タスクのループ処理
For Each t In m_TargetProject.Tasks
‘ サマリータスクや削除済みタスクを除外
If Not t Is Nothing Then
If Not t.Summary Then
If t.Start < m_ThresholdDate Then
' 汎用カスタムフィールド(Text1など)に値をセット
t.SetField m_TargetProject.FieldNameToFieldID(flagFieldName), "要確認"
End If
End If
End If
Next t
Exit Sub
ErrorHandler:
MsgBox "予期せぬエラーが発生しました: " & Err.Description, vbCritical
End Sub
ステップ2:標準モジュールからの呼び出し(Main.bas)
次に、標準モジュール側を記述します。こちらは驚くほどシンプルになります。
‘ ==============================================================================
‘ 標準モジュール: MainModule
‘ 概要: クラスをインスタンス化して処理を実行する(エントリーポイント)
‘ ==============================================================================
Option Explicit
Sub RunTaskRefactoringDemo()
Dim activeProj As MSProject.Project
Set activeProj = ActiveProject
‘ 判定基準日の設定(例:2023年12月1日)
Dim targetDate As Date
targetDate = CDate(“2023/12/01”)
‘ クラスのインスタンス化(設計図から実体を作る)
Dim processor As TaskProcessor
Set processor = New TaskProcessor
‘ 依存性の注入(DI風の初期化)
processor.Initialize activeProj, targetDate
‘ 処理の実行
processor.ProcessEarlyTasks “テキスト1”
‘ メモリ解放
Set processor = Nothing
MsgBox “すべての処理が正常に完了しました!”, vbInformation
End Sub
—
4. このリファクタリングがもたらす圧倒的なメリット
上記のコードを見て、「たったこれだけの処理に、わざわざクラスを作る意味があるの?」と感じたかもしれません。しかし、ここからが本当の価値です。
1. テストとデバッグが容易に
もしタスクの判定ロジックにバグが見つかっても、修正するのは `TaskProcessor` クラスの中だけです。標準モジュールのコードを書き換える必要はありません。
2. 再利用性の向上
別のマクロで「同じようなタスク操作」を行いたい場合、この `TaskProcessor` クラスをそのまま別のプロジェクトに持って行くだけで再利用できます。
3. コードの意図が明確(可読性の向上)
標準モジュール側が `processor.ProcessEarlyTasks` と書かれているだけで、何をしているのか一目で分かります。英語の文章を読むようにコードが読めるようになります。
—
5. 現場で陥りがちな罠とエラー回避の知見
最後に、Project VBA特有の「ハマりどころ」を共有しておきます。ここを知っているだけで、開発スピードが何倍にも跳ね上がります。
- `For Each t In Project.Tasks` の罠
Projectのタスクコレクションには、途中で削除されたタスクや特殊な要素が空(Nothing)として混ざることがあります。今回のコードのよう必ず `If Not t Is Nothing Then` でガードを入れてください。これを怠ると、突如として「実行時エラー 91: オブジェクト変数または With ブロック変数が設定されていません」に襲われます。
- フィールド名のハードコーディングを避ける
日本語環境と英語環境でフィールド名(`Text1` や `テキスト1`)が異なる問題があります。実務では `FieldNameToFieldID` を使うか、定数化して管理するのがプロの作法です。
—
まとめ:ここをクリアすれば、Project VBAの基本はバッチリです!
今回は、レガシーなコードをクラスモジュールでリファクタリングする手法について解説しました。
- 巨大なプロシージャは、役割ごとにクラスモジュールへ分割(カプセル化)する
- 標準モジュールは「コーディネーター(司令塔)」に徹し、実務ロジックはクラスに任せる
- Project特有のオブジェクトのヌルチェック(`Nothing` 判定)を徹底する
この設計思想が頭に入れば、もうあなたのコードは「スパゲッティ」とは呼ばれません。拡張性が高く、誰が見ても美しい、プロフェッショナルなVBAコードの誕生です。
ぜひ、あなたの次のプロジェクト自動化で試してみてください。応援しています!
