VBA コーディングガイドライン
このガイドラインについて
システム開発の会社には、通常コーディングルールというものが存在します。それぞれ会社ごとに異なりますが、コードの品質を一定に保てるよう各社工夫されているようです。
VB.NETやC#、Javaにはコーディングルールを集めた書籍が存在します。
これらは何もシステム開発の標準というわけではありませんが、一例として誰でも見られる形で販売されているのは素晴らしいことです。
私はVBAにおいても一応指針となるようなものが欲しいと思い、そのような書籍を待ち望んでいますがどうにも発売される気配はありません。
一応QiitaというサービスでExcel VBAコーディング ガイドライン案というものを見つけましたが、少し私と意見が異なる部分もありますので今回自分でガイドラインを作ることにしました。
このガイドラインは以下の書籍を参考に作成しています。
- リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
- プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則
- 良いコードを書く技術 -読みやすく保守しやすいプログラミング作法 (WEB+DB PRESS plus)
ただしこれは標準として誰かから認定を受けたものではありません。私が勝手に作成したものなので、参考される場合は自己責任でお願いします。
また、私自身これを完璧に厳守できているわけではありませんし、過去にブログに掲載したコードはガイドラインに準拠していません。あしからずご了承ください。
修正履歴
- 2017/01/26 初版公開
- 2017/01/29 エラー用ラベルの命名規則を追加
コーディングの原則
コードは書きやすさを犠牲にしてでも、読みやすさを重視
プログラミングは知的な創造作業であり、実際に手を動かしている時間よりも考え悩む時間のほうが遥かに長くなります。読みにくいコードは考え悩む時間をさらに引き伸ばします。したがって、書きやすさよりも読みやすさを重視すべきです。コードは人間が読むドキュメントだと考えましょう。
変数は使用する直前で宣言する
変数は使用する直前で宣言してください。変数を先頭で宣言するのは古い習慣です。変数の使用範囲が広くなりプロシージャの分割や把握が困難になりますのでやめましょう。
変数は適切な型で宣言する
変数の型にはそれぞれ用途があります。特に使い分けに困るであろう数値系について指針を示します。
- Integer … ループ変数など、一般的な整数に用います。
- Long … Integer型に収まりきらない大きな整数に用います。Excelシートの行・列を指す変数にはLongを用いてください。
- Byte … バイトデータを扱うのに使います。数値が255以下で足りるからといってByte型で宣言する必要はありません。
- Single … オートシェイプの座標やサイズに用います。
- Double … 一般的な実数に用います。
- Currency … 精度が求められる実数(金融系など)に用います。
- Variant … 型が特定できない場合に用います。たとえば関数の引数にIntegerとLongどちらでも対応できるようにしたい場合、Variantを用いると実現できます。
プロシージャはできるだけ1画面以内に収める
1つのプロシージャはコメント・空行を含めて20行程度に収めてください。どれだけ長くても50行までです。それ以上になる場合はロジックの見直しやプロシージャの分割を考えます。
ただしこのルールを守るためだけにマルチステートメントの乱用や、関連のない変数を纏めて宣言することは避けてください。
1行は1画面に収める
1行は80文字程度としてください。画面に収まらない場合はステートメントの改行( _)を利用します。
戻り値を使用しない自作プロシージャの呼び出しはCallを使用する
標準モジュールなどに作成したプロシージャを戻り値無しで呼び出す場合はCallキーワードを使用してください。
Call ShowResult(x)
こうするとプロシージャ呼び出しであることが際立つので可読性が向上します。
VBA組み込みの関数などを呼び出す場合はCallキーワードは不要です。
MsgBox "Hello"
オブジェクトのメソッドを呼ぶ際もCallキーワードは不要です。
Range("A1").Select
名前付けの原則
識別子とは名前のことです。つまり変数名・定数名・プロシージャ名・オブジェクト名などを指します。
名前付けの一般的な原則
英単語は原則短縮せずにそのまま書く
たとえばts、tarS、tgtShなどという変数名ですぐに意味が分かるでしょうか。これは「ターゲットシート」のつもりで作られた変数です。分かる人は分かるかもしれません。しかし誰でもすぐにわかるtargetSheetという変数名に変更すべきです。
サンプルコードの変数名は短いのでそういうものだと思われているかもしれませんが、実際にはserverListLastRowのように長い変数名もつけることができます。
コーディング途中は短縮系の変数名を使っても構いませんが、プロシージャが出来上がったら速やかに適切な名前に置換しましょう。
なるべく安直で捻りのない名前をつける
何の捻りもない、見たままの名前をつけましょう。犬の名前は、「イヌ」です。間違っても「ポチ」などという名前をつけてはいけません。もちろん、プログラミングの場合ですが。
日本語文字の使用
VBAでは識別子に日本語文字「漢字・かな・カナ」を使用できます。個人的に作成するもので、オフショア開発などで海外へ出す予定がなければ識別子に日本語文字を用いても構いません。
一般的にシステム開発のプログラミングでは識別子に英語を用いますが、VBAはシステム開発というよりEUC(エンドユーザーコンピューティング)、つまり利用者・業務担当者によるちょっとした効率化の範疇で使われる機会が多いので、別物と考えるべきです。
コーディングの一般原則で述べたように、コードは書きやすさを犠牲にしてでも、読みやすさを重視すべきなので、英語に自信がないなら日本語で堂々と命名してください。
ただし用途はEUCに限ります。システム開発でVBAを用いる場合は必ず英語を用いてください。
ローマ字の日本語は使用しない
menseki = teihen * takasa / 2 といったローマ字変数はNGです。たまたま式の中で出てきたから意味が通じますが、単品で出てきたときに「面積」なのか「免責」なのか不明瞭で誤解のもとになります。
わからない英単語は調べれば済みますが、わかったつもりの誤解は余計に時間を食いつぶします。
area = base * height / 2 とするか、堂々と日本語で「面積 = 底辺 * 高さ」と書いてください。
変数・定数の命名原則(英語・日本語共通)
一意にモノを特定できる名前をつける
たとえばユーザー表とサーバー表の2つを扱うマクロで、lastRowなどという名称ではどちらの表の最終行を表すのか分かりません。userLastRow、serverLastRowなど、一意に特定できる名称を用いてください。
逆にユーザー表しか扱わないマクロではlastRowで十分です。
文脈から容易に想定できる事柄は省略します。容易にというのがポイントです。
使用範囲が狭い変数は短い名前でもよい
宣言から代入、参照し終えるまでが一画面に収まるほど短い場合は変数名の単語を短縮しても構いません。これは前後の文脈から変数の役割がわかるためです。
この場合も我流の短縮系は使わず、一般的に英語圏で知られているものを用います。たとえばtargetの短縮系はtgtです。tarやtag、tgeなどと略してはいけません。
変数名に動詞は用いない
動詞は処理=プロシージャを連想させますので用いません。
変数・定数の命名原則(英語編)
システムハンガリアン記法は使わない
変数名の頭に形名を省略したものを付ける記法をシステムハンガリアンと呼びます。
たとえばlngLastRow、intSheetNumber、strUserNameといった記法です。これらはすでに古い習慣なので使用しないでください。システムハンガリアンは現在いたるところで批判されていますので、理由は検索すればすぐに見つかるでしょう。
ローカル変数はキャメル記法を用いる
変数名が複数の単語で形成される場合、単語の区切りを表すのにいくつかのスタイルがあります。
- パスカル記法 … UserNameのように単語の先頭を大文字にする
- キャメル記法 … userNameのように最初の単語だけ先頭小文字で2つ目以降の単語は先頭を大文字にする
- スネーク記法 … user_nameのように小文字の単語をアンダーバーで区切る
- 大文字記法 … USER_NAMEのように大文字の単語をアンダーバーで区切る
このうち、プロシージャ内で用いられるローカル変数にはuserNameのようにキャメル記法を用いてください。
モジュールレベル変数はパスカル記法を用いる
モジュールレベル変数には、UserNameのようにパスカル記法を用いてください。
パラメーター変数(仮引数)はスネーク記法を用いる
プロシージャのパラメーター変数(仮引数)はuser_nameのようにスネーク記法を用いてください。
VBAの関数群の仮引数はパスカル記法になっていますが、自分で書いたコードはあとで読む必要が生じますので、どのような変数なのかスタイルで判別できたほうが便利です。折角4種類の記法があるので使い分けてしまいましょう。
定数は大文字記法を用いる
定数はUSER_NAMEのような大文字記法を用いてください。昔から定数には大文字が用いられてきました。
変数・定数の命名原則(日本語編)
複数形を表す日本語変数
英語と違い日本語では単数と複数を区別しない単語がほとんどです。「社員」のコレクションや配列に「社員s」などと命名するスタイルもありますが、不自然なのでやめましょう。
複数系は安直にデータ型を後置詞として「社員コレクション」や「社員配列」とすれば良いでしょう。
その単語の複数系を表す自然な単語があればそちらを用いても構いません。たとえば「○○セット」「○○集」「○○リスト」といった言い方があります。 この場合だと「社員リスト」というのが良いでしょうか。
漢字ばかり連続させない
一般的な日本語にも言えますが、「当月売上表最終行」などと漢字を連続されると目疲れします。「当月売上の最終行」や「当月売上リスト最終行」などと適宜「かな・カナ」を混ぜていきましょう。
日本語にこだわりだすとつい日本語らしい言い回しを用いたくなりますが、すでに日本語化している外来語は積極的に用いてください。
プロシージャの命名原則(英語・日本語共通)
Subプロシージャ名とFunctionプロシージャ名は「動詞+名詞」とする
Subプロシージャ名とFunctionプロシージャ名は原則、GetUserName、ShowResultなど、動詞+名詞で命名します。
Propertyプロシージャ名は「名詞」とする。
Propertyプロシージャ名はUserNameのように名詞のみとします。
プロシージャの命名原則(英語編)
PublicおよびFriendプロシージャにはパスカル記法を用いる
Publicプロシージャ、FriendプロシージャにはGetUserNameのようにパスカル記法を用いてください。
プロシージャは何もつけなければ標準でPublicなので、Publicと明示しないものもパスカル記法を用います。
Privateプロシージャにはキャメル記法を用いる
PrivateプロシージャにはgetUserNameのようにキャメル記法を用いてください。
モジュール名の命名原則(英語編)
標準モジュール・クラスモジュール・シートモジュール・フォームモジュールに付けるオブジェクト名※はパスカル記法を用いてください。
※オブジェクト変数名ではありませんので注意してください。
たとえば以下のような宣言があったとき、personがオブジェクト変数、PersonClassがクラスモジュールのオブジェクト名です。
Dim person As PersonClass
ユーザー定義型・列挙型の命名規則(英語編)
ユーザー定義型・列挙型の名称はパスカル記法を用いてください。
内部の要素にもパスカル記法を用いてください。
エラー用ラベルの命名規則
「Err:」や「ERROR:」としているケースもありますが、Errはエラーオブジェクト、ErrorはOn Errorキーワードとして使用されているので別の名前にしたほうが良いでしょう。
特にこだわりがなければ、エラー用のラベルは「Error_Handler:」としてください。複数必要な場合は「Error_Handler1:」などとナンバリングしてください。
コメントに関する原則
コードからすぐに分かることをコメントに書かない
コードがやっていることを逐一コメントしているケースが見受けられますが、古い習慣なので今すぐやめましょう。
コメントはひどいコードの埋め合わせに使うものではありません。
トリッキーなことをしているコードにはコメントを書く
いったい何をしているのかすぐにわからないようなコードは、コメントを書いておきます。
要約コメントを書きたくなったら、プロシージャ分割も検討する
複数行にまたがるコードには要約コメントは書くのは良いことです。しかしそうしたコードを別プロシージャに分割しプロシージャに適切な名前をつければその名前がそのままコメント代わりになります。
コメントは嘘つき
コードは適宜メンテされますが、その際にコメントの書き換えもれがよく発生します。したがってコメントは往々にして嘘をつきます。書いた当初は本当だったことが、コードの書き換えによって嘘になるのです。
理想はコード = ドキュメントです。適切な変数名、プロシージャ名をつけることでコメントの必要性がなくなります。
まずい変数名を補完するコメントは書かない。
その変数が何であるかは、変数名そのものが説明すべきことです。
たとえば
Dim uLstLR As Long 'UserListのLastRow(ユーザーリストの最終行)
なんていうコメントは最悪です。
Dim userListLastRow As Long
これで事足ります。
コードを翻訳するだけのコメントは書かない
時々このようなコメントを見かけます。
Range("A1").Select 'A1セルを選択する
これはコードが言ってることを日本語で繰り返しているだけです。やめましょう。
コードの意味はできるだけコードに説明させる
このようなコメントも多いです。
Range("A1").Value = Now '開始時刻欄に現在時刻を代入する。
このようにコードに説明させることも検討しましょう。
Dim startTimeCell As Range: Set startTimeCell = Range("A1")
startTimeCell.Value = Now
あるいは日本語変数を用いると更に分かりやすくなります。
Dim 開始時刻セル As Range: Set 開始時刻セル = Range("A1")
開始時刻セル.Value = Now
コメントにはプログラマーの意図を残す
なぜそう書いたのか、コードから伝わってこないことを書き残すためにコメントを書きましょう。逆にコードから容易に読み取れることはコメントする必要はありません。
コメントで履歴管理しない
コードの変更履歴をコメントに残すケースがありますが、コードが汚れるのでやめましょう。それはバージョン管理システムでやることです。
もしバージョン管理システムが無いなら、単にファイルごとコピーして履歴管理しましょう。使わなくなったコードはコメントアウトするのではなく、削除してください。
プログラミングは知的な作業です。余計なコメントで散らかったコードでは、十分に創造性を発揮できません。