「スパゲッティコード」を断ち切る:20行の境界線がVBAを救う理由
現場で動いているマクロを見てほしい。数百行に及ぶ一つの `Sub` プロシージャの中に、シートのクリア、データの抽出、計算、そして出力までが詰め込まれていないだろうか?
それは「プログラム」ではなく「ただの作業記録」だ。
多くの開発者が陥る罠は、VBAを「上から順に実行される指示書」だと勘違いしていることにある。しかし、真に堅牢なシステムを構築するなら、VBAを「独立した知性を持つ部品の集合体」として設計しなければならない。
今日から君が守るべき鉄則は一つ。「1つのプロシージャを20行以内に収める」ことだ。なぜこれほどまでに厳格なのか? それを解説しよう。
—
なぜ「20行」なのか?——認知的負荷と保守性の最適解
20行という制限には科学的な根拠がある。
1. 視認性: スクロールせずにコードの全体像が把握できる限界値が概ね20行だ。これを超えると、脳は「文脈の把握」ではなく「迷路の探索」を始める。
2. 単一責任の原則 (SRP): 20行あれば、一つの小さなタスク(例:特定のシートの最終行を取得する、特定の条件でフィルタをかける)を完遂するには十分だ。もしこれに収まらないなら、その関数は「やりすぎ」ている。
3. テストの容易性: 巨大な関数はテストが地獄だ。細分化された関数は、個別に即座に動作検証ができる。
—
実践:巨大マクロを「パーツ」に解体する
例えば、「データを読み込み、集計して、CSVに書き出す」という処理を考えてみよう。これを一つのプロシージャに書くのは素人のやり方だ。
悪い例(保守不可能)
Sub DoEverything()
‘ 100行続く巨大な処理
‘ ここでエラーが起きると、どこで失敗したか特定するのに数分かかる
‘ シートの指定、計算、保存が混在していて再利用が不可能
End Sub
良い例(設計されたコード)
各処理を独立させ、`Main` プロシージャは「指揮官」に徹する。
‘ メイン処理:全体の流れを定義するだけ(まさに指揮官)
Public Sub RunDataProcessing()
Dim data As Variant
‘ 1. データのロード
data = LoadDataFromSheet(“DataSheet”)
‘ 2. データの加工
ProcessData data
‘ 3. 結果の保存
SaveToCSV data, “C:\Output\Result.csv”
End Sub
‘ 各パーツは20行以内。特定の役割に集中させる
Private Function LoadDataFromSheet(sheetName As String) As Variant
‘ エラーハンドリングをここに集約すれば、全体が堅牢になる
On Error GoTo ErrHandler
LoadDataFromSheet = Worksheets(sheetName).UsedRange.Value
Exit Function
ErrHandler:
MsgBox “データの読み込みに失敗しました”, vbCritical
End Function
—
堅牢な設計のための3つの掟
現場で「なぜこのコードは壊れないのか?」と評価されるために、以下のルールを徹底せよ。
1. 引数を活用し、グローバル変数を排除せよ
プロシージャ間で値を共有するのにグローバル変数を使うのは、バグの温床だ。必ず `Arguments`(引数)として値を渡し、戻り値を受け取る。これにより、各関数は「入力が決まれば出力が確定する」という純粋な関数となる。
2. エラーハンドリングは「境界」に置く
巨大なマクロだとエラーの追跡が困難だが、細分化されていれば、どの関数でエラーが起きたか即座にわかる。重要な外部リソース(ファイルやDB)に触れる関数には、必ず `On Error` を仕込むのがプロの流儀だ。
3. 命名は「動詞+名詞」で意図を明確にする
`DoIt()` や `Sub1()` といった名前は即座に削除しろ。`FetchReportData()` や `CleanExpiredRecords()` のように、その関数が「何を目的としているか」を関数名だけで語らせるのだ。
—
さあ、リファクタリングを始めよう
明日からの君の業務は、「コードを書く前に、タスクを最小単位に分解する」ことから始まる。
もし、今手元にあるマクロが50行を超えているなら、それは「負債」だ。半分に切り出し、別の名前をつけ、引数で繋ぐ。たったそれだけで、君の書くVBAの品質は劇的に向上し、修正のたびに冷や汗をかくことはなくなるだろう。
コードは書く量ではなく、「いかに整理されているか」が、そのエンジニアの価値を決める。この原則を胸に、美しいコードを書いてくれ。
