リーダブルコードは何度も読み返すべき良書だと言われています。しかし一度読んだ本を何度も読み返すのは、頭からであれ部分的にであれ、正直結構めんどくさいです。
少しでも読み返す際のめんどくささを減らせたらいいなと思い、要約することにしました。
対象範囲は1~13章までです。14~15章は実際のコードに技法を適用していく内容になっており、サンプルコードありきの内容なので割愛します。
実装時に
「こういう時はどうやったら読みやすくなるんだっけ?」
と思った場合にサッと確認できる目次のような感じで使っていただけると幸いです。
理解しやすいコード
- 例えば複雑な処理を三項演算子で1行にまとめたコードは、if else を使って書かれたコードよりも優れていると言えるのか。
- コードは他の人が最短時間で理解できるように書かなければならない。他の人という言葉には、半年後の自分も含まれる。
- コードは短い方がいい。しかし理解するまでにかかる時間を短くすることの方が大切。
命名
- 変数の値やメソッドの動作を表すような、具体的で、明確な単語を選ぶ。単位などの情報を盛り込んでもいい。名前に情報を詰め込む。
- 類語辞典を使って調べるのもあり。
- 汎用的な名前は避ける。生存期間が短い、かつ、ある汎用的な単語より多くの意味を持たない場合はその限りではない。(つまり相応の理由がない限りは使わない)
- ループ処理のi、jなどは問題ない。しかしイテレーターが複数ある時はもう少し具体的な名付けをした方がいい。
- スコープが小さければ短い名前でもいい。スコープが大きい場合、名前に情報を詰め込んで明確にすべき。
- 頭文字や省略形は、新しいチームメンバーが意味を理解できるなら問題ない。プロジェクト固有の省略形は避けるべき。
- 名前から情報が損なわれなければ、不要な単語を削除してもいい。
- 命名規約を設ける場合はプロジェクト内で一貫性を持たせることが大切。
- 他の意味と間違えられることはないのかを何度も考える。誤解されないような命名をする。
- 限界値を含む変数 => min, maxを用いる。
- 範囲指定 => first, lastを用いる。
- 包含/排他的範囲 => begin, endを用いる。
- 真偽値 => is, has, can, shouldなど使う。否定形ではなく肯定形のほうがよい。
- 意味に対して先入観を持たれているであろう単語(慣習的に「この変数名なのでこういうデータだろう」みたいに思われそうなものなど)をそのまま使わない。
コードの見た目
- コードを書くより読む時間の方が多いので、見た目の美しさは大切。余白、配置、意味のある順序などで整形する。
- 一貫性のある改行を行う。それが難しい場合、共通部分を関数にまとめるなどして改行しやすくすることもできる。
- カンマやイコールの位置を揃え、縦の線を揃える。
- ランダムではなく、意味のある順番に並べる。
- 整列には手間がかかると思われているが、筆者の経験上そこまで手間ではないらしい。もし手間になるようであれば、その時はやめればいい。
- 既存のスタイルに合わせて一貫性を保つことのほうが、正しいコードスタイルよりも大切。
コメント
- コードからすぐにわかること(新しい情報を提供しないこと)はコメントに書かない。
- 名前を補完するためにコメントを使わない。その場合は名前を変える。
- コードを書いている時の自分の考えをコメントに書く。
- TODO, FIXME, HACK, XXX などの記法でコードの欠陥を書く。コードの品質や状態、改善の方向を示すことができる。
- 定数にコメントをつける。定数を決めた時に頭の中で考えていたこと(なぜその定数はその値なのかという背景)を記録する。
- 他人が読んだときに質問されそうなことを書く。ハマりそうな罠、ファイルやクラスの全体像についてなど。
- 関数内部の塊に対してコードをうまく要約したコメントをつける。
- コメントは正確で簡潔に。曖昧な代名詞を避け、情報密度の高い言葉を使う。
- 入出力の実例を書く。コーナーケースなどを書くといい。
- インラインコメントで名前付き引数を実現する。
ループとロジック
- 条件式の引数は左側に調査対象(変化する)を、右側に比較対象(あまり変化しない)を置く。
- 条件は否定形より肯定形を使う。
- ifで分岐させる条件の並び順にこだわる。単純な条件を先に書く。もしくは関心を引いたり目立つ条件を先に書く。これらの優劣は状況によって変わるので場面で判断する。
- 三項演算子は、それによって簡潔になる場合にのみ使用する。基本的にはif elseを使用した方がいい。行数を短くするよりも、他人が最短時間で理解できる書き方をする。
- do whileは避ける。コードは上から下に読むのが自然だから。
- 関数から早く返す。ネストを浅く保つためにも早期リターンを心がける。
- ド・モルガンの法則を使って条件式の可読性をあげる。
- 短絡評価を多用しない。簡潔に使える場合はいいが、あとで他の人が読むときにわかりにくくなる場合は避ける。
- 論理式が複雑になってしまう場合は、実現したいことの反対を考えるのも一つの手。重なっている部分を見つけたい => 重ならない部分を見つける みたいな。
変数
- 式を表す名前の変数に式を代入する。大きな式を分割できる。また、簡潔な名前の変数を用いると式の内容が要約されて読みやすくなる。
- 役に立たない一時変数は削除する。複雑な式を分割していない、式をより明確なものにしていない、重複コードの削除になっていない、などの条件に当てはまる一時変数は不要。
- 中間結果を保持する変数を削除する。処理するのを先延ばしせず、早めに処理してしまえば中間結果を保持する変数はなくてもいい。
- 変数のスコープを狭くする。大きなスコープの変数は追跡が難しい。クラス内のメンバー変数であっても、クラスが大きければ追跡しにくい。ローカル変数にするなどしてスコープを狭める。
- 変数を操作する場所を減らす。一度だけ値を設定したり、定数にしてイミュータブルなものにするなど。
コードの再構成
- プロジェクト固有の関数から、その関数の本来の目的とは関係のない処理を、別関数として切り出す。ただしやりすぎると逆に読みにくくなる。
- 切り出したものは汎用関数やヘルパーとして扱うといい。
- 関数には一度に一つのことだけをさせる。
- 関数が行なっているタスクをすべて列挙して、タスクごとに関数を分割する。
- 人間がどのように考えるかを重視したコードを書く。まずコードの動作を簡単な言葉でわかりやすく説明し、その説明に合わせてコードを書く。
- わかりやすく説明->実装 の手法は、大きなコードの塊に対しては再帰的に適用してゆく。説明->コード分割->分割されたコードに対して説明...みたいに。
- 過剰な機能は持たせない。
- 不必要なコードを削除する。
- 標準ライブラリを積極的に使う。ライブラリで何ができるのかを把握するために、定期的にドキュメントに目を通す。