プロフェッショナルへの第一歩:Project VBAで「タスク管理エンジン」を設計せよ
こんにちは。現場で泥臭い自動化と格闘し、時にその美しさに魅了されているアーキテクトです。
多くのエンジニアが「マクロの記録」から入り、標準モジュールに手続き型のコードを羅列するフェーズで止まってしまいます。しかし、MS Projectの強力なオブジェクトモデルを真に操るには、「カプセル化」という武器が必要です。
今回は、標準モジュールに依存せず、タスクという概念を独立した「オブジェクト」として扱うためのアーキテクチャ設計を伝授します。ここをクリアすれば、あなたの書くコードは「使い捨てのスクリプト」から「堅牢なエンジン」へと進化します。
—
1. なぜ「クラスモジュール」なのか?
VBAにおいて、標準モジュールは「手続きの集まり」です。しかし、プロジェクトという複雑な生き物を扱うには、データと処理をひとまとめにする「クラスモジュール」が不可欠です。
- 保守性の向上: タスクの属性(名前、期間、コスト)が変わっても、ロジックを一箇所直すだけで済む。
- 再利用性: 一度作ったクラスは、別のプロジェクトファイルでもそのまま流用可能。
- 隠蔽: 余計な内部ロジックを隠し、直感的なプロパティだけで操作できる。
—
2. 構築:Taskオブジェクトを設計する
まずは、VBAプロジェクトにクラスモジュールを追加し、名前を `cTask` としてください。これが、あなたの「タスク管理エンジン」の核となります。
クラスモジュール:cTask
‘ cTask.cls
Option Explicit
‘ 内部でTaskオブジェクトを保持するためのプライベート変数
Private pTask As MSProject.Task
‘ コンストラクタ的な役割(初期化)
Public Sub Initialize(ByVal targetTask As MSProject.Task)
Set pTask = targetTask
End Sub
‘ プロパティ:タスク名を外部から安全に取得・変更する
Public Property Get Name() As String
Name = pTask.Name
End Property
Public Property Let Name(ByVal value As String)
pTask.Name = value
End Property
‘ メソッド:このタスクがクリティカルパスかどうかを判定するビジネスロジック
Public Function IsCriticalStatus() As Boolean
‘ 複雑なロジックをここにカプセル化する
IsCriticalStatus = pTask.Critical
End Function
‘ メソッド:進捗率を安全に更新する
Public Sub UpdateProgress(ByVal percent As Integer)
If percent < 0 Or percent > 100 Then Err.Raise 9999, , “進捗率は0〜100で指定してください”
pTask.PercentComplete = percent
End Sub
—
3. 実践:管理エンジンを動かす
次に、標準モジュールでこのクラスを呼び出します。ここで重要なのは、MS Projectの重いオブジェクト(`ActiveProject.Tasks`)を直接触らず、`cTask` というラッパーを介することです。
標準モジュール:MainEngine
Sub ManageTaskEngine()
Dim t As MSProject.Task
Dim oTask As cTask
‘ タスクを一つずつ処理する
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ クラスのインスタンス化
Set oTask = New cTask
oTask.Initialize t
‘ オブジェクトとして操作する
Debug.Print “処理中: ” & oTask.Name
‘ クリティカルパスなら進捗を100%にする例
If oTask.IsCriticalStatus Then
oTask.UpdateProgress 100
End If
End If
Next t
End Sub
—
4. プロが教える「陥りやすい罠」
① `Nothing` の罠
Project VBAで `For Each` を回す際、消去されたタスクや空の行に遭遇することがあります。常に `If Not t Is Nothing Then` を入れるのが、安定稼働させるための「プロの嗜み」です。
② メモリの解放
小規模なら問題ありませんが、数千タスクを扱う場合、クラスのインスタンスをループ内で生成し続けるとメモリリークの原因になります。必要に応じて `Set oTask = Nothing` を明示的に呼び出し、オブジェクトのライフサイクルを制御してください。
③ 属性の直接参照を避ける
`Task.Name = “…”` と直接書くのではなく、今回のように `Property Let` を通すことで、「名前を変更した瞬間にログを出力する」といった付加機能(フック)を、呼び出し元を修正することなく追加できます。これが設計の柔軟性です。
—
最後に:コードの向こう側へ
ここまで理解できれば、あなたは単なる「マクロ作成者」から「システムアーキテクト」への第一歩を踏み出したと言えます。
Project VBAは、ExcelやAccessとは異なる独特の「時間軸」を持っています。その時間軸を制御するエンジンを、オブジェクト指向で設計する。このスキルは、今後どのようなプログラミング言語を学ぶ際にも必ず役に立つ「本質的な武器」です。
次は、`cProject` というクラスを作り、プロジェクト全体を管理する司令塔を作ってみてはいかがでしょうか。応援しています。また、現場でお会いしましょう。
