歴3年がおしえるVBAコードを書くための9つのアドバイス

今回のアドバイスは「VBAもっといい感じに書けないかな?」ってパターンを想定している。初心者の場合は【超入門】VBAはIf文For文を覚えれば『破壊的』に使える理由から見てみるといい。

さっそくだが、あなたにコードの可読性が高く改修しやすいVBAコードが書けるようになる9つのアドバイスを紹介していこう。

アドバイス 1: Private を使いわける

1つのモジュール内でしか使わないFunctionやSubプロシージャ、Property。他のモジュールで使うことがないならPrivateを最初につけること。

Privateを使うとつぎのメリットがある。

  • 1つのモジュール内でしか使わないことがパッと見でわかるため可読性が高い
  • 他のモジュールから参照できなくなるためムダなバグがなくなる
  • 改修時に1つのモジュールだけ影響範囲を考えればいい、バグの特定がしやすい

たとえばつぎのように書くことで「あ~この関数( or プロシージャ)はこのモジュールでしか使わないんだな。」ってことが一瞬でわかる。

' -- Main.bas モジュール --

' Private がついてないので、他のモジュールから Call で呼び出せる
Sub mainProcess()

  Call somethingProcess()

End Sub


' Private がついているので、書いてあるモジュール内でしか関数が使えない
Private Function somethingFunction() As String

End Function


' Private がついているので、書いてあるモジュール内でしか Call で呼び出せない
Private Sub somethingProcess()

End Sub

アドバイス 2: 変数は使う直前に書く

めっちゃ重要。変数はなるべく使う直前に書く(宣言)こと。変数のスコープ(広さ)が狭いほうが可読性が高く、修正や改修がしやすい。

とくにVBAでは、なぜかSubプロシージャの最初で変数をズラッとならべてるコードが多い。コードを読むのがストレスになるので使う直前に変数を書く(宣言)すること。

たとえば悪い例といい例を見てみよう。

' -- 悪い例 -- よくあるコード

Sub process()

  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim wsB As Worksheet
  Dim i As Long
  Dim n As Long

'
' -- 40行くらいのDim宣言がつづき... --
'

  Set ws1 = Sheets("Sheet1")
  Set ws2 = Sheets("Sheet2")
  Set wsB = Sheets("Sheet3")

'
'
' -- ここで100行ぐらいの長い処理 --
'
'

' ここからはじめてws1, ws2, i, nの変数を使う
  For i = 1 To 100
    ws1.Cells(i, 1) = "main process"
  Next i

  For n = 2 To 200
    ws2.Cells(n, 2) = "sub process"
  Next n

' このプロシージャではけっきょくwsBの変数を使ってなかったりする

End Sub
' -- いい例 -- 

Sub process()

'
'
' -- 例として、ここで100行ぐらいの長い処理 --
' 実際に100行以上あるプロシージャは分割すること
'
'

' 使う直前に変数を宣言する
  Dim i As Long ' iの変数スコープがここから
  Dim main_process_sheet As Worksheet
  Set main_process_sheet = Sheets("Sheet1")
  
  For i = 1 To 100
    main_process_sheet.Cells(i, 1) = "main process"
  Next i ' iの変数スコープここまで


' 使う直前に変数を宣言する
  Dim n As Long ' nの変数スコープがここから
  Dim sub_process_sheet As Worksheet
  Set sub_process_sheet = Sheets("Sheet2")
  
  For n = 2 To 200
    sub_process_sheet.Cells(n, 2) = "sub process"
  Next n ' nの変数スコープがここまで

' wsB変数は消す

End Sub

アドバイス 3: 変数・定数の型をしっかり設定する

型を設定すれば、文字列や数値、はたまた配列なのかパッと見て分かるようになる。

つぎの例を見て、パッと見でわかるコードはどっちだろうか?

' -- 悪い例 --

Dim end_message
Dim i
' -- いい例 --

Dim end_message As String
Dim i As Long

アドバイス 4: 適切な名前をしっかりつける

変数や定数、引数などには適切な名前をつけること。名前をちゃんとつけないと人でいえば、「おまえ」とか「おい」みたいに言ってるようなもの

たとえば、つぎのように「ws1」「wsZZ」みたいな変数があったらどうだろう?どんなことに使う変数か分かるだろうか?

' -- 悪い例 --

Sub aa()

  Dim wsA As Worksheet
  Dim wsZZ As Worksheet

End Sub

下記のコードのほうがどんな変数なのか、分かりやすくイメージしやすい。

' -- いい例 --

Sub converteDataToSheet()

  Dim print_sheet As Worksheet
  Dim data_master_sheet As Worksheet

End Sub

アドバイス 5: なるべくグローバル変数を使わない

グローバル変数は使わないようにしよう。どこで変数宣言が始まって、どんな型なのか分からなくなりコードがカオスになる。また、変数のスコープと呼ばれるものも広くなるのでおすすめしない。

代わりにプライベート変数を使うか、プロパティとして別モジュールに分けるようにするといい。

下記で悪い例といい例を比べてみよう。

' -- 悪い例 --

Dim data As String

'
'
' -- ここで100行ぐらいの長い処理 --
'
'

Sub converteData()

  data = ← ここの変数にどんな型データを入れられるか100行以上戻らないと分からない

End Sub
' -- いい例 --

'
'
' -- ここで100行ぐらいの長い処理 --
'
'

Sub converteData()
  
  ' プライベート変数にする
  ' data変数には文字列型のデータを入れられることがすぐにわかる
  Dim data As String 
  data = 

End Sub

アドバイス 6: シートオブジェクト名でコードを書く

シート名で書かず、シートオブジェクト名を設定してコードを書くこと。これによって、ユーザー側でシート名を変更してもムダに改修しなくてすむ

まず悪い例を見てみよう。

' -- 悪い例 --

' シート名で設定してしまうと、
' だれかにシート名を変更されたらコードを変更しなければならない
Worksheets("Sheet1").Range("A1") = "Some string"

つぎにいい例。可読性も高く変更に強くなる。

' -- いい例 --

' シートオブジェクト名で設定すれば、
' シート名が変更されてもコードを書き換えなくていい
MainProcessSheet.Range("A1") = "Some string"

ちなみに、シートオブジェクト名の設定の仕方だが、つぎのように変更すればOKだ。

  1. Excelのエディタを開く
  2. Ctrl + r キーで左側にプロジェクト表示
  3. F4 キーで左側にプロパティ表示
  4. (オブジェクト名)の項目を変更

アドバイス 7: すべての処理を1つのモジュールに書かない。必ず分割する

なるべく1つのプロシージャ、関数で1つの処理を意識してコードを書くこと。いろんな処理を1つのプロシージャ、関数に書かない。長くても30~50行ほどにとどめる。

ちなみに、関数をシンプルにすることでつぎのようなメリットがある。

  • テストしやすい
  • 処理がシンプルになり可読性、保守性があがる
  • 他の人が見てもコードが理解しやすい

アドバイス 8: 他モジュール呼び出しは モジュール.関数 or プロシージャ

改修時、少なからず既存コードを理解する作業がある。既存コードをモジュール名.関数名または、モジュール名.プロシージャ名にしていると可読性が高まる

つぎの例ではMainモジュールから、Settingsモジュールのプロパティを呼び出している。

' -- Settings.bas モジュール --

Property Get exportFileName() As String

  exportFileName = "output-file-name"

End Property
' -- Main.bas モジュール --

Sub csvFileExport()

  ' モジュール名.関数 or プロシージャ or プロパティ で設定する
  Settings.exportFileName()

End Sub

アドバイス 9: モジュール名をしっかり設定、汎用モジュール名を設定しておく

Module1, Module2などと設定せず、Settingsなど分かりやすいモジュール名にすること。あなたが改修するとき、どこにコードを追加すればいいかすぐに理解できるようになる。

例として、5つの汎用モジュール名を用意したので参考にしてほしい。

  • Main ... 最終的な処理を実行する処理を書く
  • Libraries ... 共通処理、汎用処理を書く
  • Settings ... セルの取得、ファイルの名前設定、プロパティ など設定
  • Import ... CSVやAccessなどのインポート処理を書く
  • Export ... CSVやxlsx形式などのエクスポート処理を書く

まとめ: 可読性・改修しやすさを追求していこう

今回は、可読性、保守性を中心に9つアドバイスをしてきた。可読性・改修しやすさを追求することで、いままで書いてきたVBAコードの質が格段にアップする

VBAだけでなく、他のプログラミング言語にも通用するアドバイスだ。ちゃんと実践してくれれば、他の言語にもスムーズに挑戦できるようになるだろう。

ぜひ9つのアドバイスを参考にコーディングしていってほしい。