If文のネスト地獄からの脱却:Select Case文でつむぐ、保守性極限の条件分岐設計
開発現場で絶望的な気分になる瞬間を挙げてくれと言われたら、私は迷わずこう答える。
「10段階以上ネストした、修正不可能なIf-ElseIfの山を見たとき」だと。
業務自動化ツールを作り始めた頃は誰もがこう思う。「条件が増えたらElseIfを足せばいいや」と。しかし、そのコードが半年後にどうなるか。要件変更が入り、別の担当者がそれを修正し、さらに別の仕様が乗っかった結果、誰も全体像を把握できない「魔改造の怪物」が生まれる。バグが潜んでいても、影響範囲が怖くて誰も手を出せない。
VBAにおいて、保守性の低いコードは「技術的負債」ではなく、もはや「未来への爆弾」だ。
今回は、数々の修羅場をくぐってきたプロフェッショナルの視点から、`Select Case`文を極限まで使い倒し、「読める・拡張できる・バグらない」堅牢な条件分岐設計の極意を伝授しよう。
—
なぜ「If文の乱用」は悪なのか?
`If…ElseIf…Else`構造には、致命的な欠陥がいくつかある。
1. 認知的負荷の高さ(脳内メモリの無駄遣い)
人間が一度に脳内で正確に追える条件の深さは、せいぜい3階層までだ。4階層を超えたあたりから、開発者は条件の「否定」と「肯定」の迷宮に迷い込み、論理破綻を起こす。
2. 変更耐性の低さ
条件の順序(評価の優先順位)を変更する場合、すべてのElseIfのブロックをごっそり入れ替える必要があり、コピペミスや変数の消し忘れといったヒューマンエラーを誘発する。
3. 実行パフォーマンスの無駄
多くのElseIfが連なっている場合、VBAは上から順にすべての条件を評価していく。上流でマッチしなくても、下流まで延々と判定コストを払い続けることになる。
これらを一刀両断するのが、`Select Case`文である。
—
`Select Case` の真骨頂:基本の構文とパフォーマンスの優位性
`Select Case`は、単なる「If文の書き換え」ではない。「一つの評価対象を、複数のパターンで美しくルーティングする」ための専用構文だ。
まずは基本形を確認しよう。
Select Case 評価対象の変数や式
Case パターン1
‘ パターン1一致時の処理
Case パターン2, パターン3 ‘ 複数値のカンマ区切りも可能
‘ パターン2または3一致時の処理
Case 範囲の開始 To 範囲の終了 ‘ 数値や日付の範囲指定
‘ 範囲内一致時の処理
Case Is > 閾値 ‘ 条件演算子(Is)の活用
‘ 閾値超えの処理
Case Else
‘ すべてに一致しない場合(デフォルト)
End Select
この構文の美しいところは、「評価対象(Subject)」が最初に1度だけ評価される点にある。複雑な関数やプロパティの評価を何度も繰り返すIf文に比べ、VBAエンジンにとっても圧倒的に優しく、高速に動作する。
—
【実践】実務で使えるプロダクションコード:堅牢なデータ仕訳エンジン
単なる文法解説では終わらない。実務で即座に使える、データベースや外部ファイル連携を意識した堅牢なコードを提示しよう。
今回のシナリオはこうだ:
「未処理の受注データ一覧(CSVや別システムからのインポート想定)を読み込み、顧客ランクと金額に応じて、処理ステータスと担当部署を自動振り分けする」という業務ツール。
Option Explicit
‘ =========================================================================
‘ 業務自動化プロシージャ:受注データのステータス自動仕訳エンジン
‘ =========================================================================
Public Sub ProcessOrderData()
Dim wsData As Worksheet
Set wsData = ThisWorkbook.Sheets(“Orders”)
‘ パフォーマンス最大化のお約束
Call ToggleScreenUpdating(False)
On Error GoTo ErrorHandler
Dim lastRow As Long
lastRow = wsData.Cells(wsData.Rows.Count, “A”).End(xlUp).Row
If lastRow < 2 Then
MsgBox "処理対象データが存在しません。", vbExclamation, "処理中断"
GoTo Finally
End If
Dim i As Long
Dim customerRank As String
Dim orderAmount As Double
Dim processStatus As String
Dim assignedDept As String
' データ行ループ(1行目はヘッダーと仮定)
For i = 2 To lastRow
customerRank = Trim(wsData.Cells(i, 2).Value) ' B列: 顧客ランク (A, B, C, VIP)
orderAmount = wsData.Cells(i, 3).Value ' C列: 注文金額
' -----------------------------------------------------------------
' 【核心】Select Caseによる複雑な条件分岐のルーティング
' -----------------------------------------------------------------
Select Case customerRank
Case "VIP"
' VIP顧客は金額に関わらず特命チーム
processStatus = "最優先処理"
assignedDept = "役員直轄特命室"
Case "A"
Select Case orderAmount
Case Is >= 1000000
processStatus = “要承認(高額)”
assignedDept = “第一営業部”
Case Else
processStatus = “通常処理”
assignedDept = “第一営業部”
End Select
Case “B”, “C”
‘ 複数ランクをまとめて処理しつつ、金額で分岐
If orderAmount >= 500000 Then
processStatus = “要確認”
assignedDept = “第二営業部”
Else
processStatus = “通常処理”
assignedDept = “カスタマーサポート”
End If
Case Else
‘ 異常値や未定義ランクのハンドリング(フェイルセーフ)
processStatus = “エラー:要データ確認”
assignedDept = “未割当”
End Select
‘ 結果をワークシートへ書き戻し(D列: ステータス, E列: 担当部署)
wsData.Cells(i, 4).Value = processStatus
wsData.Cells(i, 5).Value = assignedDept
Next i
MsgBox “すべての受注データの仕訳が正常に完了しました。”, vbInformation, “完了”
Finally:
Call ToggleScreenUpdating(True)
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “システムエラー”
Resume Finally
End Sub
‘ =========================================================================
‘ 画面描画制御用ヘルパー関数(高速化の定石)
‘ =========================================================================
Private Sub ToggleScreenUpdating(ByVal flag As Boolean)
With Application
.ScreenUpdating = flag
.Calculation = IIf(flag, xlCalculationAutomatic, xlCalculationManual)
.EnableEvents = flag
End With
End Sub
—
コードの設計思想:なぜこの書き方が「プロ」なのか?
上記のコードには、現場で生き残るための設計思想が随所に組み込まれている。
1. ネストの美学(内部でのIf文の許容範囲)
`Select Case`の中にさらに`Select Case`、あるいは`If`文を置くことは、条件が直交している(独立している)場合において非常に有効だ。上記のコードでは、大枠として「顧客ランク」で大別し、その中の細部として「金額」を判定している。これにより、判定基準がどこに属しているのかが一目でわかる。
2. `Case Else` の絶対的死守
「そんなデータは絶対に入ってこない」という楽観主義は、システム開発において最大の罪である。外部連携ファイルやユーザー入力は、往々にして想定外のゴミデータを持ち込む。`Case Else`を用意し、未定義の値が入ってきた場合でも、システムが沈黙せず「エラー状態」として安全にハンドリングするフェイルセーフ設計を徹底している。
3. マジックナンバーの排除と拡張性
将来、「新ランク『S』が追加された」「金額の閾値が変更になった」という要件変更が来たときを想像してほしい。If文のジャングルであればどこを直すべきか迷うが、`Select Case`であれば、該当する`Case “S”`のブロックを新設するだけ、あるいは条件値を書き換えるだけで完結する。影響範囲が局所化されているため、テストも最小限で済む。
—
チーフアーキテクトからの最終提言
VBAのコードの品質は、書き手の「思考の整理度合い」をそのまま映し出す鏡だ。
場当たり的なIf文の追加は、その場しのぎの快楽と引き換えに、未来の自分や同僚から「コードを読み解く時間」という貴重な資産を奪う。
明日から、いや、今書いているそのコードから、`If…ElseIf`の連打を見つけたらペンを止め、こう自問してほしい。
「この条件分岐は、`Select Case`で美しく統率できないか?」と。
その小さな意識の変革こそが、あなたの作る業務自動化ツールを「お荷物マクロ」から「会社のインフラとなる強固なシステム」へと昇華させる唯一の道である。
