1年目から身につけたい! チーム開発 6つの心得

第4章 わかりやすい名前を付けよう―無理なく自然なメソッド・変数の命名

この記事を読むのに必要な時間:およそ 5 分

見た目,設計ときたら,次は名前付けだね。変数や関数の名前付けで困ったこと,あるんじゃないかな?

えっ? いつも適当に付けてるから,悩んだことないですよ。名前って,そんなに大事なんですか?

おいおい……そういうのは良くないな。プログラミングの半分は設計で残り半分は名前付け,と言ってもいいくらいに重要なことなんだよ?

そ,そんなに!?


名前が付いていない条件に名前を付けたり,それぞれの機能によりわかりやすい名前を付けたりするのは,とても大事なことだよ。それに,良い名前付けができるようになれば,自然と良い設計もできるようになってくるね

そう言われると,聞きたくなってきました……!


複雑な条件には名前を付けよう

if文などで条件式を書くとき,いくつもの条件を組み合わせた複雑な条件式が必要になることがあります。しかし長すぎる条件式は,あとで読むと,何を判別するための条件であったのか,書いた本人ですらわからなくなることがよくあります。このような場面では,条件式に理解しやすい名前を付けるとよいでしょう。

条件式を別の関数に分ける

たとえばJavaScriptにおいて,ファイル名の拡張子からJPEGファイルあるいはPNGファイルであると判断できたものだけを処理したい場面を考えます。JPEGファイルと判断する拡張子は次の4種類とします。

  • JPEG
  • JPG
  • jpeg
  • jpg

またPNGファイルと判断する拡張子は次の2種類とします。

  • PNG
  • png

これを素直に書くとリスト1のようになります。しかし,これでは条件文が長すぎて読みづらいです。

リスト1 長すぎる条件式

function doSomething(fileName) {
    var extension = getExtensionFromFileName(fileName);

    // 条件式が長すぎて読みづらい
    if (extension === "JPEG" ||
        extension === "JPG" ||
        extension === "jpeg" ||
        extension === "jpg" ||
        extension === "PNG" ||
        extension === "png") {
        // ファイルに対して処理を行う
    }
}

そこでリスト2のように,JPEGファイルの判別をする個所はisJPEGPNGファイルの判別をする個所は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 {
  /* 切断状態の処理 */
}

著者プロフィール

足永拓郎(あしえたくろう)

株式会社クリアコード所属。デスクトップや組み込みソフトウェアの自由を求めて活動中。


結城洋志(ゆうきひろし)

株式会社クリアコード所属。Firefox黎明期からアドオン開発を手がけ,業務上もMozilla製品の技術サポートを担当。代表作は「ツリー型タブ」「テキストリンクなど。また,日経Linux誌にて「シス管系女子」を連載中。

コメント

コメントの記入