【VBA】構造化された”良いコード”の書き方(SubとFunction、エラー処理)

データ分析

はじめに

第2回までで、VBAの基本的な処理(条件分岐、ループ)を学びました。しかし、作りたいものが複雑になるにつれて、すべての処理を一つのSubプロシージャ(Sub...End Subの塊)に書き連ねていくと、コードが長大化し、解読や修正が非常に困難になります。

今回は、コードを整理整頓し、再利用しやすくするための「構造化」という重要な概念を学びます。その中心となるのが**SubFunctionの使い分け**、そして予期せぬエラーに対応するためのエラー処理です。これができると、あなたのコードは単なる「動くコード」から「良いコード」へと進化します。

1. Subプロシージャ – 仕事をこなす手順書

Subは「Subroutine(サブルーチン)」の略で、一連の連続した処理を実行するための手順書です。これまで私たちが書いてきたコードはすべてSubプロシージャでした。

Subの主な特徴は以下の通りです。

  • 値を返さないSubは一連の動作(セルの色を変える、データを書き出すなど)を実行するだけで、それ自体が結果の値を持つことはありません。
  • 単独で実行可能: Excelの「マクロの実行」ダイアログから直接呼び出したり、ボタンに登録したりできます。
' 「特定の処理」を実行するSubプロシージャ
Sub FormatReport()
    ' 見出しを太字にする
    Range("A1:D1").Font.Bold = True
    ' A列の幅を自動調整する
    Columns("A").AutoFit
End Sub

2. Functionプロシージャ – 値を返す計算機

Functionは、何らかの計算や処理を行い、その結果として一つの値(数値や文字列など)を返す機能を持っています。Excelのワークシート関数(SUMVLOOKUPなど)の自作版と考えると分かりやすいでしょう。

Functionの主な特徴は以下の通りです。

  • 値を返すFunctionは必ず「戻り値(返り値)」と呼ばれる結果を返します。
  • 単独では実行しないFunctionは他のSubFunctionから呼び出されたり、ワークシートのセルに数式として入力されたりして使われます。

例:税込み価格を計算するFunction

' Function Function名(引数1 As 型, ...) As 戻り値の型
Function CalcTaxIncluded(price As Double) As Long
    Const TAX_RATE As Double = 0.1 ' 消費税率10%
    
    ' Function名と同じ名前の変数に結果を代入することで、値が返される
    CalcTaxIncluded = price * (1 + TAX_RATE)
End Function

このFunctionを、別のSubから呼び出して使うことができます。

Sub ShowPrice()
    Dim productAPrice As Double
    productAPrice = 5000

    ' 作成したFunctionを呼び出し、結果を変数に格納
    Dim taxIncludedPrice As Long
    taxIncludedPrice = CalcTaxIncluded(productAPrice)

    ' 結果をメッセージボックスで表示
    MsgBox "税込み価格は" & taxIncludedPrice & "円です。"
End Sub

このように、特定の計算処理をFunctionとして部品化(モジュール化)することで、同じ計算が何度も必要になったときに、そのFunctionを呼び出すだけで済むようになります。

3. 引数(ひきすう) – プロシージャに情報を渡す

上記のCalcTaxIncluded(price As Double)price As Doubleの部分を**引数(ひきすう)**と呼びます。引数は、プロシージャ(SubFunction)を呼び出す際に、外部から情報を渡すための入り口です。

引数を使うことで、プロシージャはより汎用(はんよう)的になります。例えば、税率も引数として渡せるようにすれば、将来税率が変わってもFunctionを修正する必要がなくなります。

' 税率も引数で受け取るように改良
Function CalcTaxIncluded2(price As Double, taxRate As Double) As Long
    CalcTaxIncluded2 = price * (1 + taxRate)
End Function

Sub ShowPrice2()
    ' 呼び出す際に、具体的な値を2つ渡す
    Dim result As Long
    result = CalcTaxIncluded2(5000, 0.1)
    MsgBox result
End Sub

4. エラー処理 – 予期せぬ事態に備える

作成したVBAが、常に想定通りのデータや環境で使われるとは限りません。ファイルが見つからなかったり、数値が入るべきセルに文字列が入っていたりすると、VBAはエラーを出して停止してしまいます。

On Error GoTo [ラベル名]という構文を使うと、エラーが発生した際に処理を中断せず、指定した場所にジャンプさせることができます。これにより、エラー発生時にユーザーに分かりやすいメッセージを表示したり、処理を安全に終了させたりすることが可能になります。

例:ゼロ除算エラーを回避する

Sub DivisionCalculator()
    On Error GoTo ErrorHandler ' エラーが起きたらErrorHandler:へジャンプ

    Dim numerator As Double
    Dim denominator As Double
    Dim result As Double

    numerator = 100
    denominator = 0 ' 本来はユーザー入力などを想定

    result = numerator / denominator
    MsgBox "計算結果: " & result

    Exit Sub ' 正常終了時はエラー処理をスキップ

' エラー処理の本体
ErrorHandler:
    MsgBox "エラーが発生しました。0で割ることはできません。"
End Sub
  • On Error GoTo ErrorHandler: この行以降でエラーが発生すると、ErrorHandler:と書かれた行までジャンプします。
  • Exit Sub: 正常に処理が完了した場合、ErrorHandler:の処理を実行せずにプロシージャを抜けるために記述します。
  • ErrorHandler:: エラー発生時の処理を記述する場所を示すラベルです。

まとめ

今回は、VBAコードを構造化し、品質を高めるための重要な概念を学びました。

  • Sub: 処理を実行する手順書。単独で実行できる。
  • Function: 計算などを行い、結果の値を返す部品。他のプロシージャから呼び出して使う。
  • 引数: プロシージャに外部から情報を与え、汎用性を高める仕組み。
  • エラー処理On Error GoToで予期せぬエラーに対応し、プログラムの安定性を高める。

これらの概念を使いこなすことで、あなたのVBAプロジェクトは格段に管理しやすく、そして頑健になります。次回は、いよいよ外部のCSVファイルなどからデータを取り込み、分析の準備をする方法について解説します。

コメント