Excel VBA 逆引き集 | 標準モジュール整理

Excel VBA
スポンサーリンク

ねらい:標準モジュールを「整理・分離・見える化」して保守を軽くする

VBAは増築しやすい反面、「同じ処理が散らばる」「責務が混ざる」「どこに何があるか分からない」になりがち。標準モジュールを意図的に整理すれば、修正範囲が明確になり、品質が安定します。初心者でもすぐ使えるテンプレと、重要ポイントを深掘りして解説します。

  • 目的: 責務ごとにモジュールを分け、命名・可視性・共通ライブラリ化で壊れにくく
  • 基本方針: 「役割別モジュール+命名規約+Public/Privateの使い分け+共通ヘッダ」
  • 重要ポイント(深掘り):
    • まず「責務の分離」。UI・業務ロジック・I/O・Config・共通基盤を分ける。
    • Public/Privateで「外に見せる関数」を最小化。モジュール内の内部関数はPrivateに。
    • 入口を揃え、開始・終了・例外・ログ・進捗の共通枠で包む。

モジュール構成テンプレ(役割別に揃える)

  • ModApp(基盤): 開始・終了、最適化スイッチ、共通メッセージ
  • ModConfig(設定): Configシート読み取りヘルパー
  • ModIO(I/O): シート/ファイルの読み書き、最終行/列の取得
  • ModLogic(業務ロジック): 計算・判定(純粋関数)
  • ModService(ユースケース): IO×Logicの組み合わせ(業務処理の本体)
  • ModUI(入口): ボタン/メニューからの起動、完了メッセージ
  • ModProgress(進捗・停止): ステータスバー、プログレスバー、キャンセルフラグ
  • ModLog(記録): Logシート出力、ステータス、ファイルログ(必要時)

重要ポイント(深掘り)

  • 「分け方」が命: どこを見れば何があるか直感で分かる状態を作る。
  • 1モジュール1責務: 2つ以上の責務が紛れているなら分割候補。
  • 横断機能(App/Progress/Log)は共通化: すべての処理が同じ枠を使う前提。

モジュールの「骨組み」テンプレート(共通ヘッダ+可視性)

' ===== ModService: 社員取込ユースケース =====
' 役割: IOとLogicを組み合わせて「社員取込」を完了させる
' 公開: Run_EmployeeImport(入口)
' 依存: ModApp, ModIO, ModLogic, ModLog, ModProgress, ModConfig
Option Explicit

' 入口はPublic(UIや他モジュールから呼ばれる)
Public Sub Run_EmployeeImport()
    On Error GoTo ErrHandler
    AppEnter "社員取込 開始"
    LogToSheet "Start", "社員取込"

    ' 設定(Configから)
    Dim inputSheet As String: inputSheet = GetConfigString("INPUT_SHEET")
    Dim outputSheet As String: outputSheet = GetConfigString("OUTPUT_SHEET")

    ' データ取得(IO)
    Dim data As Variant: data = ReadInput(inputSheet)

    ' 業務ロジック(Logic)
    Dim clean As Variant: clean = NormalizeEmployeeData(data)
    Dim result As Variant: result = AddValidationFlag(clean)

    ' 出力(IO)
    WriteOutput outputSheet, "A1", result

    LogToSheet "Finish", "社員取込"
    AppLeave True
    MsgBox "社員取込が完了しました。"
    Exit Sub

ErrHandler:
    LogToSheet "Error", Err.Number & " - " & Err.Description
    AppLeave True
    MsgBox "失敗: " & Err.Description, vbExclamation
End Sub

' 内部ヘルパーはPrivate(外へ見せない)
Private Function NormalizeEmployeeData(ByVal data As Variant) As Variant
    ' ...(配列で整形)...
End Function

Private Function AddValidationFlag(ByVal data As Variant) As Variant
    ' ...(配列で判定)...
End Function
VB

重要ポイント(深掘り)

  • 共通ヘッダで「役割・公開・依存」を明記: 読んだ人が迷わない。
  • Public/Privateの線引き: 入口はPublic、内部はPrivateで外部から触れさせない。
  • Option Explicit徹底: 全モジュールに入れる。未宣言変数事故を根絶。

命名規約テンプレ(迷わない名前にする)

  • モジュール名: ModApp/ModIO/ModLogic/ModService/ModUI…(頭にMod)
  • 入口Sub: Run_XXXXX(例:Run_EmployeeImport)
  • ヘルパー関数: 動詞+目的語(GetConfigString、ReadInput、WriteOutput)
  • Private関数: 動詞+詳細(NormalizeEmployeeData、AddValidationFlag)
  • 定数/列挙: 全大文字+アンダースコア(例:CONST PATH_EXPORT)、Enumで意味付け
' 定数と列挙(ModApp または専用ModConst)
Public Const DATE_FMT As String = "yyyy-mm-dd_HHNNSS"

Public Enum RunMode
    ModeDev = 0
    ModeProd = 1
End Enum
VB

重要ポイント(深掘り)

  • 「見て分かる」名前が最強: コメントより名前。
  • 入口の命名が揃っていることが操作性を上げる: ボタン割当やメニューが楽。

使い回しライブラリを「1か所」に集める(重複排除)

よく使う汎用処理は共通化。重複があれば「共通モジュールへ移動」して参照側を書き換える。

' ModIO: よく使うI/O
Option Explicit

Public Function LastRow(ByVal ws As Worksheet, ByVal col As Variant) As Long
    LastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
End Function

Public Function LastCol(ByVal ws As Worksheet, ByVal headerRow As Long) As Long
    LastCol = ws.Cells(headerRow, ws.Columns.Count).End(xlToLeft).Column
End Function

Public Function ReadRegion(ByVal topLeft As Range) As Variant
    ReadRegion = topLeft.CurrentRegion.Value
End Function
VB

重要ポイント(深掘り)

  • 同じコードを見つけたら統合: 「コピペ増殖」はバグの温床。
  • 戻り型を揃える: Rangeではなく配列で返すとロジック分離がしやすい。

整理・棚卸しテンプレ(現状を可視化する)

既存プロジェクトの「どのモジュールに何があるか」を一覧化して、重複・命名違反・Option Explicit漏れを可視化。

' ModAudit: モジュール棚卸し
Option Explicit

Public Sub AuditModules()
    Dim wb As Workbook: Set wb = ThisWorkbook
    Dim ws As Worksheet
    On Error Resume Next
    Set ws = wb.Worksheets("Audit")
    If ws Is Nothing Then Set ws = wb.Worksheets.Add: ws.Name = "Audit"
    On Error GoTo 0
    ws.Cells.Clear
    ws.Range("A1:D1").Value = Array("モジュール", "プロシージャ", "Public/Private", "Option Explicit")

    Dim r As Long: r = 2
    Dim vbComp As Object
    For Each vbComp In wb.VBProject.VBComponents
        If vbComp.Type = 1 Then ' 1=標準モジュール
            Dim hasExplicit As Boolean
            hasExplicit = InStr(1, vbComp.CodeModule.Lines(1, WorksheetFunction.Min(20, vbComp.CodeModule.CountOfLines)), "Option Explicit", vbTextCompare) > 0

            Dim lineCount As Long: lineCount = vbComp.CodeModule.CountOfLines
            Dim i As Long
            For i = 1 To lineCount
                Dim ln As String: ln = vbComp.CodeModule.Lines(i, 1)
                If ln Like "Public Sub *" Or ln Like "Public Function *" Or ln Like "Private Sub *" Or ln Like "Private Function *" Then
                    ws.Cells(r, 1).Value = vbComp.Name
                    ws.Cells(r, 2).Value = Trim$(Split(Replace(ln, "(", " ("), " ")(2)) ' 名前をざっくり抽出
                    ws.Cells(r, 3).Value = IIf(InStr(1, ln, "Public", vbTextCompare) > 0, "Public", "Private")
                    ws.Cells(r, 4).Value = IIf(hasExplicit, "Yes", "No")
                    r = r + 1
                End If
            Next
        End If
    Next

    ws.Columns.AutoFit
    MsgBox "棚卸しを作成しました。(Auditシート)"
End Sub
VB

重要ポイント(深掘り)

  • 棚卸しで「整理の対象」を明確化: Public過多、Option Explicit漏れ、似た関数名を発見。
  • 先に見える化→次にリファクタ: 「何がどこにあるか」を確信してから動く。

リファクタリング手順テンプレ(安全に整理する)

  1. 棚卸し(AuditModules)を作成。現状を把握。
  2. 命名を正す(入口Run_XXXXへ、モジュールは役割名へ)
  3. Publicを絞る(入口以外はPrivateへ、他モジュールからの直接呼び出しを禁止)
  4. 重複コードを共通化(ModIO/ModAppなどへ移動)
  5. 責務分離(UI/Service/Logic/IO/Configへ分割)
  6. Option Explicitを全モジュールへ(未宣言変数を潰す)
  7. テスト実行(主要処理が動くか。ログと進捗表示も確認)

重要ポイント(深掘り)

  • 一度に全部やらない: 小さく切って、毎回動作確認。
  • Public削減が最大効果: 外部参照を減らすほど壊れにくい構造になる。

依存の向きを揃える(逆流禁止ルール)

  • UI → Service → Logic / IO / Config / App / Log / Progress
  • 禁止例: LogicからRange操作(IOを通す)、ServiceからUserForm直接制御(UIへ戻す)
' 悪い例(Logicでセル操作)
Public Function CalcBad(ByVal ws As Worksheet) As Double
    CalcBad = WorksheetFunction.Sum(ws.Range("A2:A100"))
End Function

' 良い例(IOで読み→Logicは計算)
Public Function CalcGood(ByVal arr As Variant) As Double
    Dim i As Long, s As Double
    For i = 1 To UBound(arr, 1)
        s = s + Val(arr(i, 1))
    Next
    CalcGood = s
End Function
VB

重要ポイント(深掘り)

  • 依存の向きが揃うとテスト可能になる: Logicは配列だけで動く。
  • 副作用の封じ込め: Range/Workbookへの書き込みはIOだけが担当。

モジュール輸出入(.basで管理)でバージョン管理に備える

  • 手順: VBAエディタ→ファイル→ファイルのエクスポート(.bas)
  • メリット: Gitなどで差分管理できる。整理の履歴が残る。
  • 運用: 「共通ライブラリ」は別リポジトリにして他ブックへ流用

重要ポイント(深掘り)

  • 1モジュール=1ファイル: 役割ごとに独立。
  • 差分が見える: 命名やPublicの変更がレビューしやすい。

例題で練習(貼って試せる)

  • 例1:棚卸し(AuditModules)を実行して、Public/PrivateとOption Explicit漏れを確認。
  • 例2:命名整理(Run_XXXXX、ModXXXXX)へ揃える。
  • 例3:重複統合(最終行取得やステータス更新をModIO/ModAppへ移動)。
  • 例4:責務分離(Logicからセル操作を排除し、IO→Logic→IOの流れへ置換)。
  • 例5:Public削減(入口のみPublic、他はPrivate)。動作確認。

実務の落とし穴と対策(ここが肝)

  • 落とし穴1:整理で動かなくなる不安
    • 対策: 小さく刻む+毎回テスト+ログ・進捗で見える化。
  • 落とし穴2:Publicが多すぎて関係が複雑
    • 対策: 入口だけPublic。他はPrivateに。Serviceからのみ呼ばせる。
  • 落とし穴3:命名がバラバラで探せない
    • 対策: モジュール先頭に共通ヘッダ(役割・公開・依存)を必ず入れる。
  • 落とし穴4:Option Explicit漏れ
    • 対策: 全モジュールへ挿入し、実行時に未宣言変数で止める。
  • 落とし穴5:重複コードが消せない
    • 対策: 共通モジュールを用意して「必ずそこを使う」ルールに。既存呼び出しを書き換える。

スターター手順(最短導入)

  1. AuditModulesで棚卸しを作り、現状を見える化。
  2. 命名・ヘッダ・Option Explicitを全モジュールに適用。
  3. Public整理+共通化(ModApp/ModIO/ModProgress/ModLog)。
  4. 責務分離(UI/Service/Logic/IO/Configへ移動)。
  5. .basエクスポートでバージョン管理に乗せ、変更履歴を残す。

タイトルとURLをコピーしました