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

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

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

適切な長さの名前を付けよう

プログラムを書いていると,条件式だけでなく,変数名,関数名,クラス名,モジュール名,ファイル名など,何かに名前を付けるという機会が非常に多くあります。適切な名前が付けられているコードは読みやすく,メンテナンス性や拡張性が高くなります。しかし,何をもって適切な名前かどうかを判断すればよいのでしょうか?

名前は,⁠それが何であるか」をきちんと表していることが最も重要です。しかし,いくら正確でも「大宇宙銀河系内太陽系第3惑星地球における……」のように長すぎる名前は読み書きしにくいし,似たような名前が並ぶと区別もしにくいでしょう。短すぎず長すぎもしない適切な長さは,適切な名前の必要条件です。

とはいえ,機械的に名前の長さを何文字以上/何文字以下の範囲に収めればよいというものでもありません。適切な名前を付けたら結果的に適切な長さになっていた,というのが理想です注1)⁠適切な長さの適切な名前を付けるための考えかたとはどういうものでしょうか。

注1)
変数に使える名前の長さや文字の種類に厳しい制限がある言語では,その限りではありません。

短すぎる名前,長すぎる名前

良いコードの書きかたについて語られる場面では,1文字変数は忌避されることが多いです。また,1文字でないにしても極端な省略がなされることもあります。そのようなコードは,一見しても何のためのコードなのかわかりにくいです。リスト8を見て,前提知識なしにいったい何のコードなのか判別できるでしょうか?

リスト8 極端に名前が短いコード

getSs: function() {
  var a = MailServices.accounts;
  var ss = a.allServers;
  var r = [];
  for (let i = 0, m = ss.length; i < m; ++i) {
    let s = ss.queryElementAt(i, Ci.
nsIMsgIncomingServer);
    if (s.type == "none")
      continue;
    r.push(s);
  }
  return r;
},

気づいた人もいるかもしれませんが,これは前章で例として挙げたアドオンtbforce-auth-at-startupにおける,⁠認証が必要な受信サーバの一覧を得る」処理です。そう言われてからコードを読んでみると,ssって何だ? 代入文を調べると……ああ,サーバの配列を表してるのか」getSsって何だ? ……ああ,サーバの一覧を取得するメソッドということか」と,なんとなく意味を読み取れるのではないでしょうか。しかし,すべてのコードがこんな調子では,読み進めるたびにいちいちつまずいてしまって,ストレスを感じてしまいますね。

では,変数や関数の名前に十分な量の情報が含まれていさえすれば問題ないのかというと,そうとも限りません。情報量の多すぎる名前,つまり長すぎる名前にもデメリットはあります。リスト9は,それぞれの変数が何を表すものであるかがわかるようになるべく多く情報を盛り込んだ例ですが,これをすんなり読めるでしょうか?

リスト9 極端に名前が長いコード

thunderbirdAddonCollectServersArrayToBeAuthenticated: function() {
  var thunderbirdAccountManagerService = MailServices.accounts;
  var allThunderbirdServerObjectsArray = accountManager.allServers;
  var returnedFoundThunderbirdServerObjectsArray = [];
  for (let index = 0,
       maxIndex = allThunderbirdServerObjectsArray.length;
       index < maxIndex; ++index) {
    let thunderbirdServerObject = allThunderbirdServerObjectsArray
      .queryElementAt(index, Ci.nsIMsgIncomingServer);
    if (thunderbirdServerObject.type == "none")
      continue;
    returnedFoundThunderbirdServerObjectsArray
      .push(thunderbirdServerObject);
  }
  return returnedFoundThunderbirdServerObjectsArray;
},

余白が少なくて,端的に言うと非常に「黒い」コードです。文字数が多いと単純に読むのにも時間がかかりますし,このような画面では自分が今どこを読んでいるのかを見失ってしまいがちです。

文脈に基づいて名前を付けよう

名前が短すぎたり長すぎたりするのは,文脈(コンテキスト)を適切に設定できていないからです。文脈をきちんと設定することによって,必要な情報を盛り込みつつも無駄な情報が削ぎ落とされた,1~2単語程度の適切な長さの名前を付けられます。

文脈とは,そのコードにたどり着くまでの間に何があったのかを説明する一連の背景事情のことです。リスト8,9のコードであれば,⁠メールクライアントのMozilla Thunderbird用の,起動直後に認証を求めるようにするアドオンにおける,認証処理モジュールの,認証が必要な受信サーバの一覧を得るためのメソッド」という文脈で書かれたコードだ,と言うことができます。

文脈の中ですでに説明されていることまでもが名前に含まれていると,冗長で長すぎる名前ということになります。リスト9でいえば,⁠Thunderbird用である」⁠認証のためのコードである」といったことは文脈から自明なので,変数名や関数名には含めなくてもよいでしょう。メソッドの戻り値はサーバの一覧ですから,順当に考えてArrayクラスのインスタンスであることは自明ですし,個々のサーバを表すものは構造化されたデータなので,Objectクラスのインスタンスであることも自明です。また,localizationauthenticationのような長い単語の中には,文脈によってはフルスペルでは書かずにl10nauthのように省略することのほうが多い単語もあります。

その一方で,⁠候補になり得るすべてのサーバ」「見つかった認証が必要なサーバ」とは区別したいので,両者を見分けるためのフレーズをallServersfoundServersのように残してよいでしょう。このように,無理に1単語にすることにこだわらないで,場合に応じて2単語や3単語を選択するのもポイントです。1単語にすることにばかりこだわってしまうと,ネイティブスピーカーでも辞書でしか見たことがないようなマイナーな単語ばかりが並ぶ,初見で意味のわからないコードになってしまいます。

文脈に基づいて名前を付けなおした例がリスト10です。過不足なく情報が盛り込まれているため,最初の2つの例に比べてずっと読みやすくなっているはずです。

リスト10 適切な長さの名前のコード

collectAuthServers: function() {
  var accountManager = MailServices.accounts;
  var allServers = accountManager.allServers;
  var foundServers = [];
  for (let i = 0, maxi = allServers.length; i < maxi; ++i) {
    let server = allServers.queryElementAt(i,
Ci.nsIMsgIncomingServer);
    if (server.type == "none")
      continue;
    foundServers.push(server);
  }
  return foundServers;
},

文脈上明らかなら,1文字変数も使ってよい

文脈の中に説明が含まれていないにもかかわらず,それが何であるのかという説明が省略されていると,短すぎる名前ということになります。1文字変数が批判されるのは,まさにそれが理由です。1文字だけでは,それが何であるのかを説明するのは困難です。しかし,1文字だけでもその対象のことを正確に説明できるならば,1文字変数を使ってよい場面です。Arrayクラスのsortメソッドの比較関数における仮引数名などは,その代表でしょう。

リスト11は,サーバの配列をホスト名でソートする例です。このような比較関数は対象となる2つの要素を比較するためだけにあり,各要素は一般的に同じ種類のものであることを考えると,aServerbServerのように無理にそれ単体で意味のある名前を付けるのはかえって冗長です。

リスト11 比較関数での1文字変数

servers.sort(function(a, b) {
  if (a.hostName > b.hostName)
    return 1;
  if (a.hostName < b.hostName)
    return -1;
  return 0;
});

forループにおけるカウンタ変数も,⁠forループのカウンタ」という文脈では,iの1文字だけで十分にその意味を表現できます。むしろ,iという1文字変数はforループのカウンタ変数に使うことが極めて多いので,下手にきちんとした単語で名付けるよりも文脈がよりはっきりするという見かたもできます。

このように,文脈上適切な名前を付けるということが最も重要です。それによっておのずと,変数名が適切な長さになります。


良い名前付けと良い設計は表裏一体なんだ。良い設計なら自然と良い名前を付けられるし,問題点を整理しきれていない設計だと良い名前を付けられない。良い名前を付けようと思ったら,名付ける対象が良い設計になっていないといけないんだ。適切な名前を付けやすいかどうかは,設計の良し悪しを測る一つのバロメーターだと言えるね

うーん,でもどうしても3単語や4単語の長い名前になっちゃうんですよ……

そういうのは登場人物が足りないんだ ね。⁠AがBを使ってCをする」みたいに1つのメソッドで一気にやるんじゃなく,⁠BがCをする」⁠AはBに指示を出すだけ」みたいに処理を細かい単位に分けると,きっと良い名前を付けやすくなるよ図1

図1 一気にまとめてやらずに作業を細かい単位に分ければ,それぞれは単純になる

図1 一気にまとめてやらずに作業を細かい単位に分ければ,それぞれは単純になる

なるほど! 名前付けに困ったときは,設計を見なおす良い機会なんですね


著者プロフィール

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

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


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

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

コメント

コメントの記入