見た目、設計ときたら、次は名前付けだね。変数や関数の名前付けで困ったこと、あるんじゃないかな?
えっ? いつも適当に付けてるから、悩んだことないですよ。名前って、そんなに大事なんですか?
おいおい……そういうのは良くないな。プログラミングの半分は設計で残り半分は名前付け、と言ってもいいくらいに重要なことなんだよ?
そ、そんなに!?
名前が付いていない条件に名前を付けたり、それぞれの機能によりわかりやすい名前を付けたりするのは、とても大事なことだよ。それに、良い名前付けができるようになれば、自然と良い設計もできるようになってくるね
そう言われると、聞きたくなってきました……!
複雑な条件には名前を付けよう
if文などで条件式を書くとき、いくつもの条件を組み合わせた複雑な条件式が必要になることがあります。しかし長すぎる条件式は、あとで読むと、何を判別するための条件であったのか、書いた本人ですらわからなくなることがよくあります。このような場面では、条件式に理解しやすい名前を付けるとよいでしょう。
条件式を別の関数に分ける
たとえばJavaScriptにおいて、ファイル名の拡張子からJPEGファイルあるいはPNGファイルであると判断できたものだけを処理したい場面を考えます。JPEGファイルと判断する拡張子は次の4種類とします。
またPNGファイルと判断する拡張子は次の2種類とします。
これを素直に書くとリスト1のようになります。しかし、これでは条件文が長すぎて読みづらいです。
リスト1 長すぎる条件式
function doSomething(fileName) {
var extension = getExtensionFromFileName(fileName);
// 条件式が長すぎて読みづらい
if (extension === "JPEG" ||
extension === "JPG" ||
extension === "jpeg" ||
extension === "jpg" ||
extension === "PNG" ||
extension === "png") {
// ファイルに対して処理を行う
}
}
そこでリスト2のように、JPEGファイルの判別をする個所はisJPEG、PNGファイルの判別をする個所はisPNGと名前を付けて、それぞれを関数として抽出します。このようにすると、リスト3のように条件文がすっきりします。また、isJPEG()やisPNG()の詳細は知らなくても、JPEGファイルやPNGファイルに処理をしようとしている関数だということもわかります。
リスト2 条件式を別関数に抽出する
// JPEG ファイルの判別をisJPEG() として抽出する
function isJPEG(extension) {
return (extension === "JPEG" ||
extension === "JPG" ||
extension === "jpeg" ||
extension === "jpg");
}
// PNG ファイルの判別をisPNG() として抽出する
function isPNG(extension) {
return (extension === "PNG" ||
extension === "png");
}
リスト3 抽出した関数を使って判断する
function doSomething(fileName) {
var extension = getExtensionFromFileName(fileName);
// 条件式がシンプルになり読みやすくなる
if (isJPEG(extension) || isPNG(extension)) {
// ファイルに対して処理を行う
}
}
変数を使用する
真偽値を返す関数であっても、関数名からは戻り値の意味がわかりにくかったり、関数の使用方法が複雑すぎたりといった理由で、そのままでは条件式としての使用に適さないこともあります。このような場合は、その関数の戻り値を一度変数に代入し、簡潔かつ明確な名前を付けることで、コードが読みやすくなります。
例として、GLibというC言語用のユーティリティライブラリに含まれるg_file_get_contents()という関数を見てみます。この関数は指定したファイルの中身を取得するための関数で、取得に成功した場合には真を、失敗した場合には偽を返します。この関数を使用してファイルの取得を試み、失敗した場合はエラー処理を行うという実装を作る場面を考えてみましょう。g_file_get_contents()は真偽値が返される仕様であるため、リスト4のように、そのままif文の条件式として使用したくなります。
リスト4 条件式の中での副作用のある関数呼び出し
if (!g_file_get_contents(file_name, &contents,
&length, &gerror)) {
/* エラー処理 */
}
しかしg_file_get_contents()は4つも引数を取るため、条件式が少し込み入った記述になり、どこからどこまでが関数の引数なのか、どの範囲をif文の条件とみなせばよいのかが、ぱっと見ではわかりにくくなっています。
また、g_file_get_contents()の仕様を知らない人がこのコードをデバッグしようとしたとき、このif文による分岐が本当に正しい処理であるのかどうかをすぐには把握できないかもしれません。世の中には、今回の例のように成否を真偽値で表現する関数もあれば、成功したときには0を、失敗した場合には0以外のエラーコードを返すといった仕様の関数もあるからです。
さらに言えば、そもそも関数の戻り値が成否を表しているとも限りません。関数名からは、戻り値としてファイルの内容を返しそうな印象も受けます。この関数がこれらのどのパターンであるかは、この名前からは正確に判断することはできません。
このような場合には、リスト5のようにg_file_get_contents()の戻り値を一度succeededという名前の変数に代入するとよいでしょう。この関数の仕様を知らない人にとっても、戻り値が真の場合に成功であるという動作がわかりやすくなりますし、if文の条件式もシンプルになってコードが読みやすくなります。
リスト5 副作用のある関数呼び出しを条件式の外に出す
gboolean succeeded = g_file_get_contents(file_name,
&contents,
&length,
&gerror);
if (!succeeded) {
/* エラー処理 */
}
条件には真偽型であることがわかる名前を付ける
先ほどの例でも見たように、条件式を関数や変数にして名前を付ける際は、それが真偽型であること、そして真と偽がそれぞれ何を表すのかが明確になるような名前にするとよいでしょう。たとえば、次のような名前はYes/Noを判断しやすいためよく使われます。
- available(利用できる)、downloadable(ダウンロードできる)のような具体的な状態を表す形容詞
- connected(接続された)、succeeded(成功した)、failed(失敗した)のような具体的な動詞の受動態
- is、has、can、shouldなどの接頭辞を伴ったhasAttributeやisPNGのようなフレーズ
Rubyのメソッド名においては、真偽値を返す場合はクエスチョンマークを接尾辞として加えてconnected?のように名付けるという慣習もあります。
たとえば、筆者の足永が開発に関わるHatoholというソフトウェアにおいて、ほかのホストとの接続状態を判別するための関数がgetConnectedStatus()という名前であったことがありました。この関数は真偽値を返す関数で、真の場合には接続中、偽の場合は切断中を意味するというものでした(リスト6)。
リスト6 条件式の中の関数が何を返しているかわかりにくい
if (getConnectedStatus()) {
/* 接続状態の処理 */
} else {
/* 切断状態の処理 */
}
しかし、getConnectedStatus()という名前からは、単に「接続中」「切断中」という状態以外にも、「認証中」など、真偽値だけでは表現しきれない別の接続状態も取得できそうな印象を受けてしまいます。
このときはリスト7のように、先頭に真偽型であることを示すisを付け、また意味を解釈するうえでなくても支障のないStatusを外して、isConnected()という関数名に変更しました。これは状態を取得する関数での話ですが、状態そのものを表す変数に名前を付ける場面であれば、connectedという1単語にしてもよいでしょう。
リスト7 条件式の中の関数が真偽値を返すことがわかりやすい
if (isConnected()) {
/* 接続状態の処理 */
} else {
/* 切断状態の処理 */
}
適切な長さの名前を付けよう
プログラムを書いていると、条件式だけでなく、変数名、関数名、クラス名、モジュール名、ファイル名など、何かに名前を付けるという機会が非常に多くあります。適切な名前が付けられているコードは読みやすく、メンテナンス性や拡張性が高くなります。しかし、何をもって適切な名前かどうかを判断すればよいのでしょうか?
名前は、「それが何であるか」をきちんと表していることが最も重要です。しかし、いくら正確でも「大宇宙銀河系内太陽系第3惑星地球における……」のように長すぎる名前は読み書きしにくいし、似たような名前が並ぶと区別もしにくいでしょう。短すぎず長すぎもしない適切な長さは、適切な名前の必要条件です。
とはいえ、機械的に名前の長さを何文字以上/何文字以下の範囲に収めればよいというものでもありません。適切な名前を付けたら結果的に適切な長さになっていた、というのが理想です[1]から入手できます。
。適切な長さの適切な名前を付けるための考えかたとはどういうものでしょうか。