このブログをはじめてついに500本目の記事となりました。
いつもお読みいただいている皆様本当にありがとうございます!
今回は500本を記念し、今までの総まとめも兼ねて、
私のExcelVBAコーディング規約を紹介したいと思います。
みなさんのマイルール作りの参考にしてみてください。
- はじめに - コーディングガイドラインとは
- 基本方針
- コーディングの基本
- マクロの設計について
- 命名規則
- コメント
- オブジェクトの取得方法(マジックナンバー対策)
- 制御構文(分岐・ループ)
- プロパティ・キーワードなどの省略
- プロシージャ分割
- エラー処理
- 配列(Array)/Collection/Dictionary
- シート数式の活用(WorksheetFunction/Formula)
- マクロの速度について
はじめに - コーディングガイドラインとは
コーディングガイドライン(規約・ルール)とは、
- 変数名はこんな風に命名してください。
- 分岐・ループはこんな風に書いてください。
- Sub/Functionはこんな風に分割してください。
など、コードの書き方にルールや方針を定めたものです。
複数人で開発を行う際、コードの書き方がバラバラになるのを防ぎ、
それぞれのコードを読みやすくすることで保守性を高めるためのものですね。
また、コーディング規約はチーム開発だけでなく個人開発においても有効で、
- コードの書き方に迷う時間を減らすことができる
- 以前書いたコードが読みやすくなる
という点でコーディング効率を底上げしてくれます。
ExcelVBAerにとってはこちらの方が重要なメリットですね!
開発するマクロの規模が大きくなってきたら、
ぜひ一度マイルールを作ってみてください。
特に「迷わずコードが書ける」というのが想像以上に効果を発揮すると思います。
本記事が皆さんのマイルール作りの一助になれば幸いです(´∀`)
なお、本記事で述べる規約は「私のマイルール」であり、
私がこのルールに則って書くことで私のコーディング効率を上げようというものです。
このルールに則ることがExcelVBAの正しい書き方という訳ではなく、
あくまで「私はこのルールで書いていますよ」という紹介ですので、
そのことを念頭に読み進めていただければと思います。
では始めます。
基本方針
プログラムは「書く時間」よりも「読む時間」の方が圧倒的に長い
コードは書きやすさを犠牲にしてでも、読みやすさを重視して書くこと
コーディングの基本
変数の宣言を強制
・変数の宣言は必ず行うこと(Option Expricitにて強制すること)
親シート・親ブックの明示
・ActiveSheetに頼ったコーディングを行わないこと
・同様にSelect、Selectionに頼ったコーディングを行わないこと
マジックナンバーの禁止
・セルアドレスや列番号などにはリテラルを用いず、
定数・変数・プロパティによる定義を行うこと
・これらの定義は専用のモジュールを用意して行うのが望ましい
変数のスコープ
・変数のスコープは可能な限り小さくすること
・Public変数の利用は極力避けること
(Public定数は積極的に活用する必要がある点に注意)
コードのインデント・ネスト
・コードは制御構文(For/Ifなど)ごとに適切にインデントすること
・ネストが深くなりすぎないようプロシージャ分割を適切に活用すること
モジュールの分割
・ひとつのマクロごとに1つのモジュールを原則とし、
各モジュールごとにメインプロシージャが1つになるよう設計すること
プロシージャ(Sub/Function)の分割
・処理が大きく変わるパーツごとに適切に分割を行うこと
・汎用関数(ライブラリ)の作成を積極的に行うこと
マクロの設計について
マクロの分類
マクロは大枠で以下の3つに分類できる。
- 目の前の作業を省力するための書き捨てマクロ
- 特定の作業を自動化するためのマクロ
- 特定の業務を担う業務システム
まずは作成するマクロがどの分類にあたるかを考え、
メンテナンス性とコーディングコストの優先度を決めてから製作に入る。
(3>2>1の順にコーディング効率を犠牲にメンテナンス性の向上を考える)
コードの搭載場所
1.即席マクロ
・作業ファイル・データに直接コーディングする
・このマクロはコーディング効率を最優先とし、ガイドラインは無視してもよい。
・ただし予想に反して改修発生した場合は改修前に必ずリファクタリングを行うこと。
2.自動化マクロ
・専用のマクロブックを用意し、実行制御と対象データの選択を行う。
・データに直接マクロを記載しないこと。
3.業務システム
・共有フォルダやクラウド上にプログラムファイルを用意しそこに記載する。
・ユーザーに配布するファイルにはApplication.Runのみを記載し、
マザーファイルの修正をもってマクロの改修・修正が行えるよう設計する。
4.ライブラリ・汎用マクロ
・ライブラリは個人用マクロブックまたはアドインブックをオリジナルとする。
・編集は必ずオリジナルファイルにて行う。
・標準モジュールの分割はなるべく行わずひとつのモジュールに記述する。
・各マクロブックはそのモジュールをコピーして使用する。
以降、本記事では主に「2.自動化マクロ」におけるコーディングルールを記載する。
モジュールの設計
モジュールは以下の4種類に分けて実装する。
- 実行(UI)モジュール
- メインコードモジュール
- 定義モジュール
- ライブラリモジュール
・ボタンやイベントなどの実行制御や入力値のチェックは実行モジュールに記載し、
メインモジュールは「ユーザー入力が正常前提のコード」を記載する。
(メインロジックから例外処理を省くことでコードを簡潔に書ける)
・MsgBoxや描画のONOFF、Endによる停止などはすべて実行モジュールに書く。
(複数のメインコードを一括実行する際にこれらが阻害となるため)
・定数定義やファイル内の全マクロで使いまわす関数は定義モジュールに書く。
(簡単な改修はこのモジュールの変更だけで済むように組む)
・下位のモジュールから上位のモジュールをCallしないこと。
・適切にメインコードモジュールを分けることができている場合は、
そのモジュールで共有する変数はモジュールレベル変数で宣言してよい。
(中の全プロシージャに引数で渡すよりも可読性がよくなることが多い)
命名規則
変数名・定数名
・変数は「英字接頭辞+日本語」で命名する。
(英字接頭辞+Ctrl+Spaceによる候補入力のため)

・英字接頭辞で「オブジェクトの種類」を、
日本語部で「そのマクロにおける変数の役割」を意味づけし、
- 英語部分(構文+変数前半)だけを読めばプログラムの挙動が読める
- 日本語部分(コメント+変数後半)だけを読めばマクロの目的が読める
という読み分けができる命名を理想とする。
・接頭辞には使用するオブジェクトや取得した関数名を含む、
いわゆるアプリケーションハンガリアンを使用する。
(システムハンガリアンは使用しない)
- 良い例:行番号に「R_」、フォルダパスに「path」
- 悪い例:整数だから「lng」、文字列だから「str」
- 良い例:単独セルに「cell」、単独行に「row」、データ範囲に「DataArea」
- 悪い例:Rangeオブジェクトだからすべて「rng」
・単独の変数は先頭を小文字にし、定数や配列は先頭を大文字とする。
これは「DimかConstか」の区別ではなく、コード上で動的かどうかで分類する。
(初回代入後一度も変更する気のない変数は定数だと思って大文字始まり)
・行列番号のR,Cのみは視認性(好み)で変数であっても大文字を使用する。
よく使用する接頭辞は以下の通り。
(変数としてよく登場するものは先頭小文字、
定数としてよく登場するものは先頭大文字で記載)
| 接頭辞 | 対象変数 |
|---|---|
| R_ | 行番号 |
| R1st | 第1行番号 |
| RLast | 最終行番号 |
| RNo | 行番号定数(主にEnum) |
| C_ | 列番号 |
| C1st | 第1列番号 |
| CLast | 最終列番号 |
| CNo | 列番号定数(主にEnum) |
| cell | 単独セル |
| row | 単独行 |
| rows | 複数行 |
| column | 単独列 |
| columns | 複数列 |
| i | 一次元配列の添字(二次元はRC) |
| area | セル範囲 |
| Adrs | セルアドレス |
| TableArea | データ範囲(見出しを含む) |
| DataArea | データ範囲 |
| DateRow | データの各行 |
| DateColumn | データの各列 |
| ws | ワークシート(変数) |
| WS | 固定シート(オブジェクト名など) |
| MTWS | マスタシート |
| OPWS | 実行シート |
| CfgWS | 設定シート |
| wb | ワークブック(変数) |
| WB | 固定ブック |
| BkName | ブック名(拡張子あり) |
| BkBaseName | ブック名(拡張子なし) |
| BkPrefix | ブック名接頭部 |
| ShName | シート名 |
| path | フォルダパス |
| fullpath | ファイルパス |
| is | Bool変数、フラグ |
| cur | 現ループの値 |
| next | 次の値 |
| prev | 前の値 |
| item | Collectionなどに格納する値 |
| key | Dictionaryなどに格納する値 |
| dir | Dir関数の返り値 |
| instr | Instr関数の返り値 |
| input | InputBox関数の返り値 |
| MsgTxt | 正常MsgBox表示値 |
| ErrText | 以上MsgBox表示値 |
| Arr | 配列 |
| Clct | コレクション |
| Dic | ディクショナリ |
| Class | クラスモジュール |
| cls | クラスインスタンス |
| shp | シェイプ |
| FSO | FileSystemObject |
・接頭辞はあくまでシステム命名とインテリセンスのためにつけているので、
スコープの短い変数は「日本語のみ」で宣言してよい。
・逆にFor Each用の変数はマクロ上の意味を持たないことが多いため、
以下のように「接頭辞のみ」で宣言してよい。
Dim cell As Range For Each cell In Area集計表.Cells
・初学者にとって「どれが変数でどれが構文かわかる」ことは非常に重要なため、
本ブログの解説コードにおいては以下のように書き換えている。
Dim セル As Range For Each セル In Area集計表.Cells
・日本語部分についてはシート上の単語があればそれをそのまま用いること。
・漢字は連続6~7文字を超えると途端に視認性を悪化させるため、
助詞「てにをは」を区切り文字として適切に入れること。
(この区切り法をてにをはケースと呼びます)
Subプロシージャ名
・メインプロシージャは日本語文で定義する。
Sub 売上データを読み込んで集計表を出力する(wb売上データ As Workbook)
・前述の変数と同じく「てにをは」を省略しないこと。
特にSubプロシージャ名は漢字が連続すると視認性が悪化しやすい。
・最後の送り仮名「する」があればSub、なければFunction。
・メインプロシージャからCallするサブプロシージャは、
Privateであればマクロ上の挙動だけで名付けてよい
' 良い例 For Each ws In wb売上データ.Worksheets Call シートごとの処理(ws) Next
' あまりよくない例 For Each ws In wb売上データ.Worksheets Call 各売上データを集計表に取り込む(ws) Next ' ↑ メインプロシージャとかなり似た名前になってしまうことが多くかえって混乱する
・マスタの取り込みなどの細かい処理は、
メインプロシージャっぽく見えないよう「→」などを使って簡潔に書く。
' 良い例 Call 売上データ←商品マスタ(ws) ' あまりよくない例 Call 売上データへ商品マスタを参照する(ws)
・同じくメインプロシージャと名前が似てしまう問題として、
実行プロシージャもかなり似た名前になってしまうことが多い。
この場合、実行プロシージャに★などの記号を付けると識別しやすく、
マクロ一覧の上部にソートされるためボタンの設置等も楽になる。
Sub ★選択した売上データから集計表を出力する() Sub 売上データを読み込んで集計表を出力する(wb売上データ As Workbook)
Functionプロシージャ名
・「Get/Create/Conv/Count」などを接頭辞に日本語を接尾する。
Function GetArrセル→一次元配列(Area As Range) Function CreatWS集計表テンプレート(対象年 As Long) As Worksheet Function ConvYYYYMMDD→Date(yyyymmdd As Long) As Date
・「元/先」や「へ/を」は混乱しやすいので「→」を使用する。
・判定結果を返すFunctionは「Is」を接頭する。
Function Isユーザーの入力に不備あり(ws入力シート As Worksheet) As Boolean
・ただしモジュールのメインプロシージャがFunctionとなる場合は、
Subプロシージャと同様の命名規則とする。
Function 売上データを読み込んで集計表を出力する(wb売上データ As Workbook) As Worksheet
プロシージャの引数名
・引数のヒントが見やすいことを最優先に命名すること。
ヒントを見れば中身を見なくて済むのも関数分割の大事なポイントである。
・宣言位置に引数の説明を書くくらいなら、それをそのまま変数名した方がよい。
説明変数
・変数は値の再利用だけでなく、値に名前を付けることも大事な役割である。
この「説明変数」も積極的に利用すること。
対象日 = DateSirial(.Range("I2"), .Cells(R, C), .Cells(R, C + 1)) ' ↓書き換え Dim y As Long: y = .Range("I2") Dim m As Long: m = .Cells(R, C) Dim d As Long: d = .Cells(R, C + 1) 対象日 = DateSirial(y, m, d)
If ws処理シート.Cells(R, C) >= 10000 Then ' ↓書き換え Dim cur売上 As Long: cur売上 = ws処理シート.Cells(R, C) If cur売上 >= 10000 Then
変数の宣言位置
・変数は使用する直前に宣言すること。
・冒頭でまとめて宣言するのも悪いわけでないが、
- 関数化するときに連れていけない
- Dimより前では使っていない判断(スコープの明示)ができない
というデメリットがあるため使用する直前の宣言を推奨する。
・初期値の代入はマルチステートメントを利用して簡潔にすること。
コメント
・コメントは各ブロックの見出しとして記載する。
各処理を直訳せず、コードのまとまりで何をやっているかを記載すること。
' フィルターをクリア If 対象シート.AutoFilterMode = True Then If 対象シート.AutoFilter.FilterMode = True Then 対象シート.ShowAllData End If End If
・シングルクォーテーションを使用し直後に半角スペースを1つ入れること。
・「コメントを書くくらいなら変数名にする/関数にする」
という視点は必ず持ってコーディングを行うこと。
' 悪い例 ' 元のアクティブシートを記憶する Dim tmpWS As Worksheet: Set tmpWS = ActiveSheet
' 良い例 Dim 元のアクティブシート As Worksheet Set 元のアクティブシート = ActiveSheet
' 良い例 Call フィルターをクリアする(対象シート)
オブジェクトの取得方法(マジックナンバー対策)
列番号のEnum定義
・シートレイアウトはEnum定数にて定義する。
Public Const R1st購入データ = 4 Public Const C1st購入データ = 1 Public Enum CNo購入データ No = C1st購入データ 購入者 購入日 品物 価格 個数 金額 End Enum Public Const CLast購入データ = CNo購入データ.金額 ' メインコード For R = R1購入データ To Get最終行(ws購入データ) ws購入データ.Cells(R, CNo購入データ.金額) = ws購入データ.Cells(R, CNo購入データ.価格) + ws購入データ.Cells(R, CNo購入データ.個数) Next
・コードの可読性、改修時のコスト両面で強力な性能を誇るため、
列番号のリテラル(ベタ打ち)は絶対に行わないこと。
固定のRangeオブジェクト
・固定のRangeオブジェクトはセルアドレスを定数定義する。
Public Const Adrs購入データ_対象年 = "I2" ' メインコード ws購入データ.Range(Adrs購入データ_対象年) = Year(Date)
・ただし開発規模が大きい場合は、
ワークシートをメインオブジェクトとするクラスモジュールに定義する
' Class購入データ Public ws As Worksheet Property Get Cell対象年() As Range Set Cell対象年 = ws.Range("I2") End Property
' メインコード Dim cls購入データ As New Class購入データ Set .ws = ws購入データ cls購入データ.Cell対象年 = Year(Date)
・逆に使い捨てのマクロを作っている場合は、
長大Withステートメント+Evaluate記法を用いて構わない。
With ws購入データ .[I2] = Year(Date) End With
Worksheetオブジェクト
・選択シートなどではない固定ワークシートの指定方法は、
自ブックであればシートオブジェクト名を用いる。
・他ブックであればブック名やシート名を文字列定義してもよいが、
開発規模が大きい場合は引数のない静的Functionを推奨する。
Function MTWS商品マスタ() As Worksheet Set MTWS商品マスタ = Workbooks("~~").Worksheets("~~") End Function
・このFunctionは定数のようなものなので中の文字列を定数化する必要はない。
Workbookオブジェクト
・Worksheetと同様、静的なFunctionを用意すると便利である。
加えて「ブックを開いていなければ開く」という汎用関数を利用するとよい。
Function WB商品マスタ() As WorkBook Set WB商品マスタ = ブックを開いていなければ開く("C:\~~\~~", "商品マスタ.xlsx") End Function
・さらに規模が大きくなる場合はRangeと同様のクラスモジュールを作成する
制御構文(分岐・ループ)
Forステートメント
・ループにはなるべくForステートメントを用いること。
終了条件をループ内で判断するより事前に調べる方がコードが簡潔になる。
・ループは一つの処理につき一つずつ用意すること。
以下のコードは実行速度に差はなく、可読性は下が優れる場合が多い。
For R = 1 To 10000 処理A : 10行くらい 処理B : 10行くらい 処理C : 10行くらい 処理D : 10行くらい Next
For R = 1 To 10000 処理A Next For R = 1 To 10000 処理B Next For R = 1 To 10000 処理C 処理D Next
・Next R など、Nextに変数を書く必要はない。
これを書くくらいならループ冒頭のコメントを再掲した方が読みやすい。
' データ内の対象商品だけを処理 For R = R1st購入データ To Get最終行(ws購入データ) If Is対象商品(ws購入データ.Cells(R, CNo購入データ.商品コード)) Then '~~~~~~~~~~~~~~ End If Next ' データ内の対象商品だけを処理
・このコメントは並列のIf文とセットで意味づけすると読みやすいことが多い。
その場合はFor-If間とEndIf-Next間を改行しないこと。
For Each ステートメント
・オブジェクトの走査にはインデックスを使用したFor文は使用せず、
原則For Eachステートメントを使用する。
Do Loop ステートメント
・For/For Eachでは難しい処理を組む場合のみDo文を使用する。
・この時While、Untilはなるべく使用せず、If ~ Exit Do を使用する。
(While/Untilで書けるならそもそもForで書けることが多く、
Forで書けない複雑な処理はExitする位置を明示した方が読みやすいことが多いため)
If ステートメント
・Ifステートメントを使用する際は条件文が複雑にならないよう注意する。
・And Or が大量に連なるようなら条件文を関数化した方がよい。
If Isデータがマクロの実行条件を満たす(ws購入データ) Then
・こうしておくと、AndやOrを複雑に組む必要もなくなるうえ、
Exit Functionを活用するとよりコードが簡潔になる。
・Elseステートメントまでは使用してもよいが、
ElseIfステートメントを使う場合はその前にSelect Caseを使えないか検討する。
Select Case ステートメント
・非常に読みやすいため積極的に活用する。
・特に各Caseを「:」でまとめることができるとコードが簡潔になる。
Select Case 分岐条件 Case 1: Call ~~~ Case 2: Call ~~~ Case 3: Call ~~~ End Select
・ElseIfの代わりに「Case True」を活用してもよい。
プロパティ・キーワードなどの省略
Withステートメント
・Withステートメントは短いスコープで使用する
With Worksheets("○○") Set 対象範囲 = .Range(.Cells(R, C), .Cells(R, C + 1)) End With
・ただし「ひとつのシートだけを扱うことが明らかなプロシージャ」であれば、
Subの直後からEnd Subの直前までを丸ごとWithしてもかまわない。
Sub 集計表の書式を設定する(ws集計表 As Worksheet) With ws集計表 ' ~~ここに長めのコードが記載されていても良い End With End Sub
RangeオブジェクトのValueプロパティ
・RangeオブジェクトのValueプロパティは、
コードが横長になるのを防ぐ目的で省略してもよい。
- Cells(R, CNoシート名.要素名)で記述するコードは積極的に省略する。
- Range変数.Valueは省略しない方が読みやすい。
・当然ながらセル範囲.Valueは省略しない。(できない)
ByVal・ByRef キーワード
・ByVal/ByRefは以下のルールで記述する。
- その引数を中で書き替えないなら「省略」
- その引数を中で書き替えて使うなら「ByVal」
- その引数が結果値として受け取る用の変数なら「ByRef」
・このルールには値しか使わない変数がByRefで定義されてしまうデメリットがあるが、
一番重要な「本当に返り値として返すByRef」が目立つメリットを優先する。
Function 関数(ByVal A, ByVal B, ByVal C, ByRef D, ByVal E) ' ↓ こちらの方が「Dは中で書き替える、Eは返り値用」が目立つ。 Function 関数(A, B, C, ByVal D, ByRef E)
Private/Public キーワード
・EnumのPublicは省略しない。
・Sub/FunctionのPublicは省略してよい。
・ConstのPrivateは省略してよい。
・モジュール変数の宣言はPrivate(Dimは禁止)
配列の下限(LBound)
・Array(下限 To 上限) における下限は省略しない。
・Option Base 1 は使用しない。
Dim と New の同時宣言
・ローカル変数(インスタンス)であれば宣言と同時にNewしてよい。
Dim Dic商品リスト As New Dictionary
・FSOや同党の使い方を想定したクラスはPublicでNewしてもかまわない。
Public FSO As New FileSystemObject
オブジェクト変数のSet Nothing
・End Sub 直前のSet Nothing は行う必要はない。
・スコープを明示する目的で、
使用を終了したオブジェクト変数をその時点でNothingにすることは推奨。
プロシージャ分割
汎用関数(ライブラリ)の作成
・汎用関数は積極的に作成する。
・関数化の真のメリットは再利用性ではなく、
「コードのまとまりを要約して1行の見出しを付けること」
・2~3行のコードでも躊躇なく汎用関数にしてよい。
For R = 2 To ws処理シート.Cells(ws処理シート.Rows.Count, 1).End(xlUp).Row ' ↓ For R = 2 To Get最終行(ws処理シート, 1) ' フィルターをクリア If 指定シート.AutoFilterMode = True Then If 指定シート.AutoFilter.FilterMode = True Then 指定シート.ShowAllData End If End If ' ↓ Call オートフィルターをクリアする(指定シート)
・下の例のように「見出しコメント」がついていることも多く、
コメントが不要になることと合わせて想像以上に効果を発揮できる。
・見出しコメントを書くならその名前の関数を作ってしまうくらいの気持ちでよい。
マクロ全体のプロシージャ分割
・マクロ全体は処理ごとに細かくプロシージャ分割する。
Sub ★選択した売上データから集計表を出力する() Dim wb売上データ As Workbook Set wb売上データ = ファイルダイアログからデータファイルを選択する If wb売上データ Is Nothing Then Exit Sub If Isデータに不備があれば警告する(wb売上データ) Then Exit Sub Call Excelの自動更新を停止する Dim ws集計表 As Worksheet Set ws集計表 = 売上データを読み込んで集計表を出力する(wb売上データ) Call 集計表に商品マスタの情報を出力する(ws集計表) Call Excelの自動更新を再開する End Sub
Function 売上データを読み込んで集計表を出力する(wb売上データ As Workbook) As Worksheet Dim 対象年 As Long: 対象年 = GetYear売上データ(wb売上データ) Dim ws集計行 As Worksheet: Set ws集計行 = 非表示のシートをコピーする(TplWS集計表) For Each ws In wb売上データ.Worksheets Call シートごとの処理(ws, ws集計行) Next Call 集計表←取引先マスタ(ws集計行) Call 集計表←商品マスタ(ws集計行) Call 集計表の計算列を更新する(ws集計行) Call 集計表の書式を設定する(ws集計行) End Function
・ポイントとしては「関わるシートの種類ごとに分ける」だけでかなり見やすくなる。
上記において「集計表とマスタ」の2シートしか関わらない処理を分割することで、
一度に意識するシートの枚数をかなり限定できていることが重要。
・プロシージャは「1画面に収まる」くらいが分割の目安。
Exit Sub/Function の有効活用
・適切にプロシージャ分割ができている場合は、
Eixt Sub/Exit Functionが非常に便利なため積極的に活用する。
If メインコードを始めてはいけない条件式 Then MsgBox "○○なため、処理を中断しました。" Else メインの処理 End If ' ↓書き換え If メインコードを始めてはいけない条件式 Then MsgBox "○○なため、処理を中断しました。" Exit Sub End If メインの処理 End If
・同様にOn Error Resume Nextも積極的に活用してよい。
エラー処理
・ExcelVBAはエラートラップの機能が貧弱な代わりに、
エラーコードでデバッグ(ステップ実行)を開始できるのが便利な言語である。
・よってOn Error GoTo ○○によるエラー処理はあきらめて、
「デバッグが出たらその画面のまま電話して」
という運用に開き直った方がコーディング効率がはるかに良い。
・一人で開発するのに完璧なエラー対応は土台無理なので、
自社のマクロを作る場面においてはVBEのデバッグ機能に頼ってよい。
・想定内のエラーを処理する場合は
On Error Resume Next エラー発生の可能性があるコード If Err.Number > 0 Then
で分岐する方がGotoで飛ぶより可読性がよいことが多い。
・どうしてもエラー処理が必要な場面に遭遇した場合は、
Gotoに用いるラベルには「Errエラー名:」を用いる。
配列(Array)/Collection/Dictionary
・VBAは配列の機能が貧弱なので、
要素の動的な追加を行うコードには原則Dictionaryを使用する。
・ReDim Preserve を頑張って使ったところで大した成果は得られない。
・CollectionについてもItemなしのDictionaryで代用できるため、
配列系統の処理をすべてDictionaryに任せてしまってよい。
・Dictionary⇔Worksheetの入出力は必ずライブラリ化すること。
・配列(Array)は二次元配列をセルとやり取りして、
マクロを高速化するためだけに使うものと思えばよい。
シート数式の活用(WorksheetFunction/Formula)
・シート数式は積極的に活用する。
・特にExcel新関数群をWorksheetFunctionから使えるのが強力。
・また、Formulaによる計算も手軽なうえに超速なので、
こちらも積極的に活用する。
ws処理シート.Range("B2:B100").Formula = "=XLOOKUP(A2,商品マスタ!A:A,商品マスタ!B:B)" ' ↑こんな簡単に書けるうえに、配列を使うよりさらに早い
マクロの速度について
・マクロの速度は「遅くなってから気にする」スタンスでよい。
・初めから速度を気にしてコーディングするとロジックで迷走しやすいので、
とりあえず読みやすく書いて、遅かったらその時考えればよい。
以上!私のコーディング規約の紹介でした。
繰り返しになりますが本記事で述べる規約は「私のマイルール」であり、
私がこのルールに則って書くことでコーディング効率を上げようというものです。
このルールに則ることがExcelVBAの正しい書き方という訳ではなく、
あくまで「私はこのルールで書いていますよ」という紹介です。
本記事が皆さんのマイルール作りの一助になれば幸いです(´∀`)
長文読了お疲れさまでした!