長谷川 裕行 (はせがわ ひろゆき)
有限会社 手國堂 代表取締役
http://www.hirop.com/
テクニカルライターとして活躍。プログラミングに関する著書多数、DB Magazineなどにも多くの記事を提供している。 |
VBでは、フォームとコードが密接に関連しています。特にコントロール名はコードから直接参照することになるため、フォームデザインの段階からコーディングを意識しておく必要があります。また、フォームを基準にプログラム全体を捉え、把握しやすい構造を組み上げることも考えなければなりません。
コントロール名とコードの関係、簡潔で分かりやすいプログラム構造について考えてみましょう。
フォーム上のコントロールの多くは、コードから参照されます。読みやすく手直ししやすいコードを書くには、コントロール名にも配慮しなければなりません。
- 変数名とコントロール名 -
VBの標準的な開発スタイルは、
フォームにコントロールを貼り付け
その振る舞いをコードで記述する
という形です。つまりコード上では、変数名とともにフォームやコントロールのオブジェクト名が至る所で登場します。
変数名を適切な名前とすることの重要性は、他のプログラミング言語の解説書などでも説かれており、理解している人も多いでしょう。VBの場合、これに加えてフォームとコントロールの名前も、適切に設定しなければなりません。
- コントロール名の接頭記号 -
フォームに貼り付けたコントロールの名前は、“Text1”“Text2”、“Command1”“Command2”…のように、コントロールの種類を表す文字列に連番を付けた形に設定されます。
簡単なテスト用のプログラムなら、そのまま使用しても差し支えないでしょう。しかし、後々の改良や保守を考えれば、変数と同じように
その種類と役割が分かる
名前を付けておくことが重要になります。
標準で付定される“Text1”や“Command1”といった名前も、コントロール種別が分かるのである意味では適切かもしれませんが、それだけでは
そのコントロールがどのようなデータを扱うのか
が不明なため、後からコードを見直したときに苦労します。
変数名にデータ型を示す接頭記号(プリフィックス)を付けるように、コントロール名にはその種別を示す接頭記号を付けます。つまり、
種別を表す接頭記号 + 役割を表す文字列
という形です。
Microsoft社の推奨する接頭記号の例を表1に掲げておきます。Microsoft社の推奨する変数やオブジェクトの名前付け規則、その他のコーディング規則については、Visual Basicヘルプの「コーディング規則――基本的な考え方」に詳しく紹介されています。キーワード「コーディング規則」で検索してください。
これはあくまで例であって、従わなければならないものではありません。筆者の場合、コンボボックスはcboではなくcmbとしています(コマンドボタンを表わす“cmd”と間違えやすいので、あまりお勧めはできませんが…)。自分が、あるいは共同開発の仲間が理解できるものであれば、独自の接頭記号を使っても構いません。
コントロール名の例をいくつか挙げておきましょう。
顧客名を入力するテキストボックス:
txtCustomerName、txtCstmName
部署名を選択するコンボボックス:
cboSection
性別を選択するオプションボタン:
optGender、optMale、optFemale
表1:オブジェクト種別を表す接頭記号の例(Visual Basicヘルプファイル「オブジェクトの名前付け基準」より抜粋し、項目を編集)
- 変数とコントロールの連携 -
VBでは、フォーム上のコントロールが受け取った値を変数に格納したり、プロシージャの処理結果をコントロールに反映したり…と、フォームとコードは常に連携しています。ラベルやタイマーのように独立したコントロールを除けば、残る大半のコントロールは、コード内の変数と何らかの関わりを持っています。
従って、同じ役割をするコントロールと変数が存在することになります。そのような場合、名前の部分を同じにして
接頭記号がデータ型なら変数
接頭記号がコントロール名ならコントロール
と、区別します。かえって混乱するように思う人もいるかもしれませんが、
役割が同じなら名前も同じにする
ことを基本にしないと、コントロールと変数の関係が把握できなくなります。
- シンボル名の一貫性 -
例えば、
ユーザー名を入力するテキストボックス:
txtUserName
ユーザー名を保存する変数:
strUserName
とすれば、代入処理は
strUserName = txtUserName.Text
と書けます
以降、コード内で変数strUserNameを扱うことになりますが、このときstrUserNameが「テキストボックスtxtUserNameに入力された値」であることがすぐに分かります。異なる変数名だと、「その変数の値がどこから得られたものか」が不明瞭になってしまうのです。
逆に、関係のない変数とコントロールを同じ名前にしてしまうと、大混乱を来すのは確実です。
適切なシンボル名を付けるには、事前に使用するコントロールや変数をしっかり把握しておくことが重要です。事前設計をしっかり行い、フォームのデザイン時に適切なコントロール名を付けるようにしましょう。
後々の手直しを容易にするには、処理全体を個々の機能や役割ごとに分類・統合し、無駄な処理単位を減らして、効率的でメンテナンスしやすい形にまとめ上げることが大切です。このような考え方を、プログラムの「構造化」といいます。
- VBの開発スタイルと構造化 -
オブジェクト指向が一般的になり、「構造化プログラミング」という言葉にはノスタルジックな響きさえあります。しかし、構造化の概念が消滅したわけではありません。構造化はオブジェクト指向の根底となる、プログラミングの基本的な考え方でもあります。
VBの場合、フォームモジュールとコードモジュールが連動しており、一般的なアプリケーションを作る上では、フォームのデザインとコードの記述を分けて考えることはできなくなっています。
まず、アプリケーションのユーザーインターフェイスを構成するフォームがあり、コードの記述はそこから出発することになるため、プログラムは自ずとフォームとそこに貼り付けられたコントロールのイベントを基準として、イベントプロシージャ単位に構造化されます。
本来なら「何もないところから処理全体を分類・統合し、構造化を行っていく」という作業が必要なのですが、VBでは、それをフォームのデザインに集約させてしまえるのです。
- フォームに頼り過ぎない -
フォームを作ればコードも自然と構造化されるという仕様は、非常に便利なことです。しかし、このことを
フォームさえ作ればあとは勝手に効率的な構造ができあがる
|
|
と解釈してしまうと、コードモジュール全体の構造を見直す作業が、おろそかになってしまいます。
フォームから入るプログラミングスタイルに、すべてを任せてしまえる訳ではありません。1つのコードモジュールの中にも、処理構造を明確にするための工夫が必要です。
分かりやすく手直ししやすいプログラムを作るための基本は、コードの記述方法にあります。以下の点に注意しましょう。
・ |
BASICの気軽さを切り捨てる
VBのベースとなったBASICの気軽さも、分かりやすいプログラムにとっては邪魔なものとなります。
|
・ |
プロシージャを簡潔にする
処理の基本単位であるプロシージャを分かりやすくすることが、最も重要です。 |
以上の点について、具体的に考えていきましょう。
BASICのスタイルに慣れているVBプログラマーは意外に多いようです。VBは“BASIC”の名こそ付いていますが、基本的にBASICとはまったく異なる言語です。
- 気軽さより分かりやすさを -
VBはBASICの言語仕様を受け継いでいますが、プロシージャ単位に処理を切り分けるというスタイルは、C++などのオブジェクト指向言語から受け継がれたものです。
C++の根底にはC言語、Pascal、Algolなどの手続き型言語があり、それらの言語が持っていた構造化の概念が、VBの処理単位であるプロシージャの原点となっています。
一方BASICには、プロシージャも構造化の概念もありませんでした。そのためBASICからVBの世界に入った人の中には、プロシージャによって処理構造を形成することの意味を、理解していない人も見受けられます。
VBはBASICの気軽さを受け継いでいますが、手直ししやすいプログラムを作るためには、その気軽さを敢えて切り捨てなければなりません。
- 変数は必ず宣言する -
標準状態では、宣言しなくても変数を使用できます。その場合、変数はVariant型となります。これはBASICの仕様を受け継いだもので、一見便利なようですが、実は非常に危険な存在です。
変数名を間違って入力しても、それは「Variant型の別の変数」とみなされてしまい、いざ実行すると結果が正しくなかった…ということになります。変数名の綴り間違いを見つけるのは、非常に手間がかかります。
必ず名前とデータ型を明示して、変数を宣言してから使用することを心がけましょう。変数の宣言を強制するステートメント
Option Explicit
を、コードウィンドウの最上行(宣言セクション)に記述すると、宣言していない変数を使っていた場合に実行時エラーが発生するようになります。
複数のモジュールを用いる場合は、「ツール(T)」→「オプション(O)」メニューで「オプション」ダイアログボックスを開き、「編集」パネルの「コードの設定」で「変数の宣言を強制する(R)」チェックボックスをONにしておきましょう。すべてのモジュールの宣言セクションに“Option Explicit”ステートメントが挿入されます。
画面1:すべてのモジュールで変数の宣言を強制する
その他にも、変数名の最後が%ならInteger型、$ならString型…とみなされる型指定文字や、DefTypeステートメントで、変数名の先頭の文字による自動型宣言ができるようになっています。
このように、VBは変数の扱いに関して寛容なところがあるため、十分に注意しましょう。
- マルチステートメントを使わない -
VBには、複数の命令行を「:」でつないで1行にする、マルチステートメントという機能があります。これは、インタプリタで動作するBASICで、実行速度を上げるためによく用いられました。
しかし、VBのようにコンパイルすることが前提の言語では、マルチステートメントで行数を減らすことに、何のメリットもありません。重要な処理を見落とすなどの問題を引き起こす可能性もあるため、使わないようにしましょう。
特に、IfやForなどの制御構造にマルチステートメントを用いると、コードを一別して制御構造であることを理解することすら、難しくなってしまいます。リスト1とリスト2を見比べてみましょう。
プログラムを構造化するためには、一つひとつのプロシージャ内で行っていることを明確にし、容易に把握できる必要があります。そのためには、「1処理1行」の基本を守ることが大切です。
リスト1:マルチステートメントを使った条件分岐処理
リスト2:1行1処理に書き換えると分かりやすくなる
VBの基本処理単位はプロシージャです。無駄のない構造を構築するためには、個々のプロシージャが簡潔であることが重要です。
- 長いプロシージャを分割する -
何十行にもおよぶプロシージャは、下請けプロシージャを作って小さく・短くすることを心がけましょう。
行き当りばったりに処理を組んでいくと
本質的には同じ処理なのに
別のプロシージャとなっている
箇所がたくさん出てくることがあります。どの部分が共通しているかを見極め、1つのプロシージャとして汎用化することが大切です。
共通した処理の中の異なる部分は、引数としてプロシージャに渡します。例えばエラーメッセージを表示する処理を、その都度MsgBox関数を使って記述すると、あちこちに似たような処理が散在することになります(図1)。
そのようなときには、リスト3のような下請けプロシージャを作り、引数でメッセージを切り替えるようにします(図2)。
リスト3:エラーメッセージを表示するプロシージャ
図1:あちらこちらでMsgBox関数が呼び出されている
図2:エラーメッセージを表示する下請けプロシージャにまとめるとすっきりする
- プロシージャの定義順も重要 -
プロシージャは好きな順序で定義できます。しかし、順序に統一性がないと、コード全体の見通しが悪くなります。一般に、以下の規則を適用すると分かりやすくなるでしょう。
・ |
イベントプロシージャ:コントロールの配置順
フォームに貼り付けられているコントロールの順序に合わせておけば、ユーザーの操作と処理の流れを把握しやすくなります。
|
・ |
下請けプロシージャ:制御順または親子順
まず呼び出される順に並べ、その中にさらに子プロシージャがある場合は、親子関係の順に並べます。こうすれば、プロシージャが呼び出している下請けプロシージャを探すのに、何十行もコードウィンドウをスクロールさせる必要はなくなります。
また、イベントプロシージャ同士、下請けプロシージャ同士、孫請けプロシージャ同士…と、プロシージャの呼び出しレベル順にまとめる方法も有効です。
|
簡潔でわかりやすい構造を作るには、とにかく「似たような処理をしている箇所」を見つけて、それらを1つの下請けプロシージャとすることです。こういった「1つにまとめられそうな処理」には、例に挙げたエラーメッセージの表示処理の他に、以下のようなものが考えられます。
ファイルのオープン処理
フィールドデータをテキストボックスに表示する処理
処理結果をまとめて表示する処理
処理を終えて元のフォームに戻る処理
一覧データの表示処理
一覧データの印刷処理
他にもいろいろと見つかるはずです。プロシージャの処理が「長いな」「あちこちで同じようなことをしているみたいだな」と感じたら、それらをくくり出してまとめてみましょう。
特に、たくさんのデータ、たくさんのフォームを使う処理では、こうすることによってコードが驚くほど短く簡潔になります。
なお、大規模なアプリケーションの組み立て方や印刷処理については、第27回以降に取り上げる予定です。
|