—
進捗の「嘘」を暴け。残工数から導き出す真のタスク進捗率自動化ロジック
プロジェクトマネジメントの現場において、最も信用できない指標は何か。それは担当者が感覚で入力した「進捗率(%)」だ。
「あと少しで終わります」「だいたい80%です」――こうした主観的な報告が、プロジェクト終盤の「進捗が90%から動かない地獄」を招く。Microsoft Project(以下、MS Project)を真に使いこなすチーフアーキテクトならば、進捗率を直接入力させるような運用はさせない。
管理すべきは「残工数(Remaining Work)」である。
今回は、リソースが申告した「あと何時間かかるか」という冷徹な数字に基づき、タスクの進捗率を自動計算・同期させる堅牢なVBAマクロを伝授する。
—
1. なぜ「進捗率」ではなく「残工数」なのか
MS Projectには「達成率(% Complete)」と「作業時間の達成率(% Work Complete)」の2種類が存在する。前者は期間(Duration)ベース、後者は工数(Work)ベースだ。
実務において、メンバーが「今日は5時間働きました」と報告しても、予期せぬトラブルで「残り時間」が減っていないことは多々ある。この場合、進捗は0%であるべきだ。
設計の基本原則:
1. 残工数をマスターとする: `RemainingWork` を入力値とし、他を計算で導く。
2. アサインメント単位で計算する: タスク単位ではなく、誰がどれだけ残しているか(Assignmentオブジェクト)を積み上げる。
3. 計算の循環を防ぐ: MS Projectの自動計算エンジンとVBAの書き換えが競合しないよう、適切なプロパティ制御を行う。
—
2. 実装:残工数基準の進捗自動同期エンジン
このコードは、選択したタスク、あるいはプロジェクト全体の「残工数」をスキャンし、実績工数と進捗率を論理的に再計算する。
Option Explicit
‘—————————————————————————————
‘ Procedure : SyncTaskProgressByRemainingWork
‘ Author : Project VBA Chief Architect
‘ Purpose : 残工数(Remaining Work)を正として、進捗率を論理的に再計算する
‘—————————————————————————————
Public Sub SyncTaskProgressByRemainingWork()
Dim tsk As Task
Dim asn As Assignment
Dim totalWork As Double
Dim remWork As Double
Dim actualWork As Double
‘ パフォーマンス最適化:画面更新と自動計算を一時停止
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Application.Calculation = pjManual
Debug.Print “— 進捗再計算処理開始: ” & Now & ” —”
For Each tsk In ActiveProject.Tasks
‘ 無効なタスク(サマリータスク、空白行、マイルストーン)はスキップ
If Not (tsk Is Nothing) Then
If Not tsk.Summary And tsk.ExternalTask = False Then
‘ タスク内の全リソース割り当てを精査
For Each asn In tsk.Assignments
‘ 内部単位は「分」であることに注意
remWork = asn.RemainingWork
totalWork = asn.Work
‘ 残工数が総工数を超過している場合の整合性チェック
If remWork > totalWork Then
‘ 計画以上の工数が必要になったと判断し、総工数を上方修正
asn.Work = remWork
totalWork = remWork
End If
‘ 実績工数を逆算 (Actual = Total – Remaining)
actualWork = totalWork – remWork
asn.ActualWork = actualWork
‘ ログ出力(デバッグ用)
Debug.Print “Task: ” & tsk.Name & ” | Resource: ” & asn.ResourceName & _
” | Progress: ” & asn.PercentWorkComplete & “%”
Next asn
‘ アサインメントの変更後、タスク側のステータスを強制更新
‘ MS Projectの計算エンジンを叩き、サマリーへ反映させる
tsk.Application.CalculateProject
End If
End If
Next tsk
Application.Calculation = pjAutomatic
Application.ScreenUpdating = True
MsgBox “残工数に基づき、全タスクの進捗率を再計算しました。”, vbInformation
Exit Sub
ErrorHandler:
Application.Calculation = pjAutomatic
Application.ScreenUpdating = True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub
—
3. プロフェッショナルがこだわる設計の勘所
オブジェクトのライフサイクルと計算タイミング
MS ProjectのVBAにおいて、`Task` オブジェクトを操作する際、背後では膨大な関連計算(クリティカルパス、リソース平準化、コスト算出)が走る。
`Application.Calculation = pjManual` を指定せずにループを回すと、タスクを1つ書き換えるたびにプロジェクト全体のリスケジュールが走り、大規模な計画書ではフリーズの原因となる。「まず止める、最後にまとめて計算する」が鉄則だ。
「分」という単位の罠
MS Project内部では、工数はすべて「分」で保持されている。`Double`型で受け取るのが定石だが、UI上の「時間」や「日」への変換で誤差が出ないよう、極力プロパティ同士の演算に留め、マジックナンバーによる除算は避けるべきだ。
データベース・外部連携時の注意
このロジックをExcelや外部の進捗管理DBと連携させる場合、以下の点に注意せよ。
- 一意の識別子(UID)を使用せよ: タスク名やID(行番号)は変動する。外部連携のキーには必ず `Task.UniqueID` を使用すること。
- トランザクションの整合性: DBから残工数を取り込む際、MS Project側でタスクが削除されていた場合の例外処理を忘れてはならない。
—
4. 運用:このマクロをいつ動かすべきか
このツールは、単体で動かすよりも「リソース状況のインポート」処理の直後にフックさせるのが最も効果的だ。
1. メンバーがWebフォームやExcelで「今日の残工数」を報告する。
2. そのデータを本マクロでMS Projectの `Assignment.RemainingWork` に流し込む。
3. マクロが自動で `% Work Complete` を算出し、ガントチャートが「真実」の姿に変貌する。
マネージャーの仕事は、進捗率の数字を疑うことではない。「なぜ残工数が減っていないのか」という事実にフォーカスし、ボトルネックを解消することにある。
結論
進捗管理の本質は、過去(実績)を数えることではなく、未来(残工数)を見据えることだ。
今回紹介したVBAコードは、その「視点の切り替え」をシステム的に強制するための強固な基盤となる。コードをコピペして満足せず、あなたのプロジェクトの計算ルール(残工数が増えた時に期間を延ばすのか、リソースを増やすのか等)に合わせて、このロジックをさらに研ぎ澄ませてほしい。
それができるのは、現場の痛みとオブジェクトモデルの両方を知り尽くした、あなただけなのだから。
