上級者を目指すExcelVBA #3 『関数は適切に分割する』

プログラムを覚えたての頃は、1つの関数内に何百行もの処理を記述してしまいがちです。

しかし以下のように1つの関数を長々と書いてしまった場合、どの行で何の処理をやっているのかがパッと見たときに非常に分かりづらいです。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200881/398f60c9-da14-d0ec-a20e-fb84b4874cee.png" width = "854" />

また、長い関数内でエラーが発生すると、エラー処理で一気に末尾まで飛んでしまうデメリットもあります。

:::note alert 
<strong>長い関数のデメリット</strong>
・処理内容が把握しづらい
・エラー発生時、エラー処理で一気に末尾までスキップされてしまう
:::

そのため、関数は適切に分割することを心がけます。
　
　
# 関数は適切に分割する

どんなプログラム言語にも共通することですが、私は以下の点を心がけて関数を分割しています。

:::note 
<strong>関数の分割の目安</strong>
　・関数の長さは20～30行程度に（どんなに長くても一画面に収まるぐらいに）
　・1つの関数には1つの仕事をさせる
　・関数名には処理内容が推測しやすい名前を付ける
　・関数の上部コメントには処理内容を記述する
:::

分割の例を挙げると以下のような形です。
小さな処理の単位ごとに関数を作成し、それぞれの関数名には処理内容が推測できる名前を付けます。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200881/4d80918b-da80-0c88-af0b-a2fc852f582a.png" width = "715" />
　
　
分割した関数は、以下のように順番に呼び出してやります。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200881/ef595651-bd25-2ff6-6446-10ff13d814ad.png" width = "602" />

　
関数名とコメントを読むだけで、全体の処理の流れが把握できますね。

今回のモジュールの全体をコードで書くと以下のようになります。

```vba TextFileReader.bas
Option Explicit

'===========================================================
'
' テキストファイル読み込み用モジュール
'
' [処理概要]
'   ・test.txtを読み込み、Sheet1上のテーブルに内容を描画する
'
' [索引]
'　　□ 1.メイン処理実行
'　　　・テキストファイル読込
'　 　 ・読み込んだ内容をシートに出力
'
'===========================================================

' モジュール名
Const MODULE_NAME = "MainController"

' ファイルパス
Const FILE_PATH = "C:\test.txt"

' 文字列格納用コレクション
Private LineTxts As New Collection


'===========================================================
'
' 1. メイン処理
'
'===========================================================

' メイン処理実行
'　・テキストファイルを読み込んでシートに出力
'
Public Sub exec()
    On Error GoTo ErrHdl

    ' テキストファイル読込
    Call readTextFile
    ' 読み込んだ内容をシートに出力
    Call outputTextToSheet
ErrHdl:
    If Err.Number <> 0 Then
        Util.logError MODULE_NAME & ".exec", Err.Description
    End If
End Sub

'===========================================================
' テキストファイルを読込
'===========================================================

' テキストファイルを読込
'　・テキストファイルを開いて1行ずつコレクションLineTxtsに追加
'
Private Sub readTextFile()
    On Error GoTo ErrHdl
    Dim fNum, txt
    
    'ファイルオープン
    fNum = FreeFile
    Open FILE_PATH For Input As #Frreefile
    
    ' 1行ずつ読込
    Do Until EOF(fNum)
        Line Input #fNum, txt
        LineTxts.Add txt
    Loop
    
    ' 閉じる
    Close #fNum
ErrHdl:
    If Err.Number <> 0 Then
        Util.logError MODULE_NAME & ".readTextFile", Err.Description
    End If
End Sub

'===========================================================
' 読み込んだ内容をシートに出力
'===========================================================

' 読み込んだ内容をシートに出力
'　・LineTxtsの内容をSheet1のテーブル上に出力する
'
Private Sub outputTextToSheet()
    On Error GoTo ErrHdl
    Dim fNum, txt, lo As ListObject
    
    ' テーブルをセット
    Set lo = Sheet1.ListObject(1)
    ' 読み込んだテキストを走査
    For i = 1 To LineTxts.count
        txt = LineTxts(i)
        
        ' テーブルに描画
        lo.DataBodyRange(i, 1) = txt
    Next
ErrHdl:
    If Err.Number <> 0 Then
        Util.logError MODULE_NAME & ".outputTextToSheet", Err.Description
    End If
End Sub

```

関数は適切に分割し、モジュール内の全体像が把握しやすいプログラムを書けるよう心がけましょう。