LINE株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。 LINEヤフー Tech Blog

Blog


コードの可読性についてのプレゼンテーション紹介 vol. 2: "命名とコメント" 編

はじめに

こんにちは。コミュニケーションアプリ "LINE" の Android クライアントチームの石川です。

この記事は、 "コードの可読性についてのプレゼンテーション紹介" の不定期連載記事の第二回です。前回の記事は こちら です。

今回は、プログラム中に書く自然言語として、第二章 "命名" と第三章 "コメント" の解説をします。

第二章: 命名

プログラムを書くときは、クラスやリソースなどの様々なものに名前をつける必要があります。その名前が、正確・明確・記述的であると、コードはより読みやすくなります。この章では、どのような名前がコードを読みやすくするかについて、特に型 (クラス, インターフェース, トレイト等)、値 (変数, フィールド, パラメーター等)、および手続き (関数, メソッド, サブルーチン等) に焦点を絞って解説します。ただし、この章で解説している内容はあくまでも一般論であるため、使用する言語・プラットフォーム・プロジェクトによって命名規則が決まっている場合は、そちらを優先してください。

ここでは、名前をつける際に重要なこととして以下の三点を取り挙げます。

  1. 名前が表現する内容
  2. 文法
  3. 語の選択

1. 名前が表現する内容

名前は、命名の対象(型、値、手続き)が "何であるか・何をするか" を表現するべきです。言い換えると、その対象がいつ使われるか・どこで使われるか・どのように使われるか・誰が使うかについては、名前で表現する必要はありません。例えば、"新しいメッセージデータを受け取ったときに、その内容を表示する" という手続きを書く場合、"新しいメッセージを受け取ったとき" に着目するよりも、 "内容を表示する" に着目するとよいでしょう。すなわち、この場合は `onNewMessage` と命名するよりも、`showMessageText` とするのが好ましいです。

名前が表現する内容が "何であるか・何をするか" である利点の一つとして、その対象の責任を明確化できることが挙げられます。`showMesasgeText` と命名した場合、引数に与えられたメッセージデータは、表示以外の目的で使われるべきでないことが示されます。しかし、`onNewMessage` と命名すると、そのメッセージデータが他の目的に使われても違和感を覚えないでしょう。責任の境界が曖昧になると、操作を重複させてしまうバグの原因や、無駄に複雑な依存関係の原因になります。

しかし、この原則にも例外があります。コールバックとして定義された抽象メソッドなどは、宣言時点では何を行うかが決まっていない可能性があります。その場合は、`onNewMessage` などの "いつ・どこで呼ばれるか" という情報を用いて命名する必要があります。ただし、抽象メソッドでも目的がはっきりしている場合は、 "何をするか" で命名するべきです。

2. 文法

名前は、単なる語の羅列によって構成されているわけではなく、英文法に近い規則によって語順や語形が決定します。多くの場合、値や型には名詞・名詞句を用い、手続きには命令文を用います。例えば、 "受け取ったメッセージのテキスト" という値は `receivedMessageText` という名詞句で表現でき、"受け取ったメッセージを保存する" 手続きであれば `saveReceivedMessage` という命令文で表現できます。

プログラミング言語によってはこの他にも、形容詞・形容詞句、三人称形の動詞・助動詞やそれを用いた疑問文、前置詞を伴う副詞句を使うこともあります。例えば、形容詞・形容詞句は性質や状態を表す型や値に(例: `Iterable`, `FINISHED`)、三人称形の動詞・助動詞やそれを用いた疑問文は真理値を示す値や手続きに(例: `contains`, `isTextVisible`)、前置詞を伴う副詞句は型変換やコールバックの手続きに(例: `toInt`, `onFinished`)それぞれ使われることがあります。

文法に従がって命名をしないと、その名前によって誤解を招く恐れがあります。クリックイベントのリスナーならば `ClickEventListener` と命名するべきですが、 `ListnerClickEvent` と名前をつけてしまうと、"Listener という UI 上のクリックイベント" もしくは "Listener が発行するクリックイベント" と解釈されかねません。これを防ぐためにも、名詞句の最後の単語は最も重要な単語になっているべきですし、命令文の最初の単語はその手続を示す動詞になっているべきです。

3. 語の選択

名前に用いる単語の選ぶ際に重要なこととして、"曖昧性の少ない単語を選ぶ"、"混乱を招く省略語を避ける"、"単位を明示する"、"肯定的な単語を選ぶ" ことが挙げられます。ここでは "曖昧性の少ない単語を選ぶ" と "混乱を招く省略語を避ける" の二点について解説します。

3-A: 曖昧性の少ない単語を使う

名前を構成する単語を選ぶ際は、より情報量の多い単語を採用するべきです。例えば `checkMessage` という名前では、メッセージが存在するかを調べたいのか、フォーマットが正しいかを調べたいのか、サーバに新しいメッセージがないか問い合わせたいのか、それともある条件を満たしたメッセージをフィルターしたいのかがわかりません。それぞれ、`existsMessage`, `isMessageFormatValid`, `queryNewMessage...`, `takeMessageIf...`等と命名するべきでしょう。より情報量の多い単語を探す際は、辞書や類語辞典を利用すると良いかもしれません。

3-B: 混乱を招く略語を避ける

名前に略語を使用すると、コードを読む負担が大きくなることが多いです。略語から意味を読み取る場合、認知よりも想起を必要とすることが多く、その想起は思考に大きな負担をかけるからです。つまり、`im` という名前を見て何の定義か思い出すよりも、`instanceManager` という名前から概要を理解する方が簡単であるということです。もちろん、広く知れ渡っている略語を使うことは問題ありません。例えば "TCP" や "URL" 等は、むしろ元の名前が思い出せない人の方が多いのではないでしょうか。また、 `string` に対する `str` 等の自明な略語は、限られたスコープの中でなら使っても良いかもしれません。一方で、プロジェクト独自の略語を定義してる場合、その略語を用いた命名が必要になることがあります。その場合は、新しいメンバーにもその略語が理解できるようにコメントで解説したり、用語集を別途用意すると良いでしょう。

第三章: コメント

複雑なコードや大きなコード、直感的に理解しにくいコードには、コメントを書くことで読み手の理解を助けることができます。また、コメントを書く過程で、より読みやすいコードにするためのアイディアを思いつくかもしれません。逆を言えば十分に理解しやすいコードについては、コーディング規約によりますが、コメントを省略しても良いかもしれません。この章では、どのようなコードにどのようなコメントを書くべきかということを解説します。

コメントは、ツールのため等の特殊なコメントを除くと、ドキュメンテーションとそれ以外のコメントに分類できます。ここでは、"それ以外のコメント" を "インラインコメント" と呼びます。(場合によっては、ブロックコメントやマルチラインコメントを明示的にインラインコメントとは別に定義している場合もありますが、ここでは単純化のためその違いを無視します。)

1. ドキュメンテーション

ドキュメンテーションは、型・値・手続きなどの宣言や定義に書くコメントで、ある一定の形式に従ったコメントのことを指します。ドキュメンテーションを読むことで、コードの詳細や参照元を見ることなく仕様を理解する事ができます。ドキュメンテーションは要約を必須とし、必要であれば詳細の説明文や `@return` などのタグを付与します。

1-A: 要約

ドキュメンテーションの最初の部分は、対象が "何であるか・何をするか" を簡潔に述べた要約でなくてはいけません。コーディング規約によっては要約は完全な文ではなく、句や省略された文を用いて書きます。例えば、型や値の要約には名詞句を、手続きの要約には三人称の主語を省略した文を使うことがあります。もし、要約の形式がコーディング規約によって定義されていない場合、その言語の標準ライブラリの形式を踏襲すると良いでしょう。余談ですがこのブログポスト自体も、各段落の最初の文は基幹となる情報になるように意識して書いています。

1-B: 詳細

要約で説明しきれない事項がある場合は、より詳しい文を書き足すことで説明します。例えば、仕様の補足や典型的な使用例、返り値、制約や例外について書き足す場合があります。仮に、返り値と副作用の両方を持つ関数があるとしましょう。この場合、関数の名前とドキュメンテーションの要約は、副作用の部分に焦点を当てて説明することが多いです。ここで返り値が真偽値であったりすると、どういうときにその値が真になるかわかりにくくなります。このような場合は、返り値を説明する文を加えることで、コードの仕様を理解しやすくできるでしょう。

2. インラインコメント

インラインコメントは、その周辺のコードの要約や補足説明をするためのコメントで、コードを読み進める際に補助をする役割があります。ドキュメンテーションとは異なり、要約は必須ではありません。このコメントは、大きなコードを分割したり、非直感的なコードを説明するときなどに書かれます。

2-A: 大きなコードの分割

比較的大きな手続きがある場合、空行とインラインコメントでコードのまとまりを作ることで、手続きの流れをトップダウンに理解しやすくなります。このコメントの内容はコードのまとまりの概要、すなわちそのコードのまとまりが "何をするか・何であるか" を表現すると良いでしょう。

2-B: 非直感的なコードの説明

ライブラリのバグの回避コード等、一見すると理由のわからないコードがある場合、そのコードが必要な理由を書くと理解がしやすくなります。このコメントを書く基準としては、 "誰かが将来間違った修正・リファクタリングをしてしまいそうか" で判断すると良いでしょう。

おわりに

今回は "命名とコメント" 編として、プログラム中に書く自然言語について解説しました

次回は "状態と手続き" 編として、第四章と第五章の内容を紹介します。