プログラミング

プログラマーのバイブル(?)良書「リーダブルコード」を今更ながらまとめてみた

プログラマーのバイブル(?)である「リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック」を今更ながら読んでみたので自分なりにまとめてみます。

まとめ方は、各章で個人的に気になった部分をピックアップして説明、または箇条書きでリストアップしています。

はじめに

この書籍は「リーダブルな(=読みやすい)コード」を書くための基本的な考え方や実践方法が体系的に整理されている本です。

本書の目的は「コードをよくすること」。ではその「良いコード」の定義とは何か。

それは「読みやすいコード(理解しやすいコード)」ということです。

コーディングの中で一番大切にすべきことは「読みやすさ」

プログラミングは、コードを「書く」時間よりもコードを「読む」時間の方が多くなりがちです。

チーム開発の場合、他のメンバーが書いたコードを読む機会に多く出会います。

コードを綺麗にすることは開発効率向上やバグの発見を素早く行えるメリットがあります。

理解しやすいコードを書くことは、エンジニアが大切にすべき指標のひとつです。

1章 理解しやすいコード

  • コードは理解しやすくなけれならない
  • コードは他の人が最短期間で理解できるように書かなければならない。これが読みやすさの基本定理になる
  • コードは短くしたほうがいいが「理解するまでにかかる時間」を短くするほうが大切

理解しやすいコードは優れた設計やテストのしやすさに繋がります。

コードを綺麗に書くことは他のメンバーのためでもありますが、数ヶ月後の自分のためでもあるのです(数ヶ月前のことなんて絶対忘れてるから)。

2章 名前に情報を詰め込む

明確な単語を選ぶ

単語から何も伝わってこないものは使用を避けるべきで、もっと明確な単語がないか実装前に考える必要があります。

カラフルな単語を選ぶ

英語は表現豊かな言語ゆえ、選べる言語はたくさん存在します。以下に一例を記します。

単語代表案
senddeliver, dispatch, announce, distribute, route
findsearch, etract, locate, recover
startlaunch, create, begin, open
makereate, set up, build, generate, compose, add, new

汎用的な名前を避ける(あるいは、使う状況を選ぶ)

変数名に「tmp」や「retval」などの汎用的で空虚な名前は避けるべきです。変数名は「変数の値」を表すような名前にします。

ただし汎用的な名前でも、使う状況次第では利用できます。

例えば、変数名 tmp の場合を、以下の「2つの値を入れ替える」例で見てみます。

このような場合は「tmp」という変数名で問題ありません。

この変数の目的は「値の一時的な保管」だから。「tmp」という名前で変数の意味を伝えています。

「tmp」という名前は生存期間が短くて、一時的な保管が最も大切な変数にだけ使う。

抽象的な名前よりも具体的な名前を使う

メソッド名は、メソッドの動作をそのまま表しているような名前にするべきです。曖昧で間接的な表現は避けます。

接尾辞や接頭辞を使って情報を追加する

値の単位(hex_id, kbps など)や重要な属性(plaintext_password, html_utf8 など)を追加します。

値を変換するコードやセキュリティまわりのコード実装で有効に働きます。

名前の長さを決める

長い名前は覚えにくいし、画面を大きく占領してしまうため、できるだけ避けた方が良いです。ただ、コードの読みやすさを損なわなければ長くても問題はありません。

メソッド名や変数名に「頭文字」を付けたりや「省略形」を使うことは、新しいメンバーに対して誤解を招く恐れがあるため使用は控えるべきです(理解できるなら問題はない)。

名前のフォーマットで情報を伝える

アンダースコアやダッシュ、大文字で名前に情報を追加します。

3章 誤解されない名前

最善の名前とは「誤解されない名前」のことです。

  • 名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する
  • 限界値を示すときは「min_」「max_」を付ける
  • 範囲を示すときは「first_」「last_」を付ける v包括的範囲には「begin_」「end_」を付ける
  • ブール値は「is・has・can・should」を使ったり、肯定的で分かりやすいものを付ける
  • getXXXという名前は変数へのアクセッサの意味として認知されているため、そのような処理以外でこのメソッド名を使用しない

4章 美しさ

プログラミングの時間のほとんどは、コードを「読む」時間に費やされるので、コードは読みやすく美しくする意識が必要です。

  • コードを一つの塊と捉えて、コードのシルエットを一定に保つようにする
  • コードの「列」や「順序」を意識して読みやすく
  • 間違ったスタイルを使っているコードでも、一貫性を損なうくらいなら、その既存のスタイルを踏襲する。一貫性を保つ方が大事である

美しさを意識したコードは簡潔で読みやすく、またテストコードが埋め込みやすくなるというメリットがあります。

5章 コメントすべきことを知る

コメントの目的は読み手にコードを理解してもらうことでです。

コメントすべきではないこと

  • コードからすぐに分かることをコメントに書かない
  • コードの読みにくさを補うコメントは必要ない。コメントを書く前にコードを修正する

良いコメントとは

  • コードの背景を説明している(なぜこういう実装になっているかとか)
  • コードの欠陥を示している
  • ファイルやクラスの全体像を説明している(どんな特徴を持ったものなのかとか)。新しくジョインするメンバーのコードの理解にも役立つ
  • 実装者がハマりそうな部分を前もって指摘している

6章 コメントは正確で簡潔に

  • コメントは画面の領域を取られ、読むのにも時間がかかるため、簡潔なものにする
  • 曖昧な代名詞(「あの」や「その」など)は避ける
  • メソッドの入出力のコメントには実例(例:〇〇を入れたら〇〇が返る)を入れる

7章 制御フローを読みやすくする

条件式の式の並び順

条件式やループはできるだけ「自然」にする。以下の条件式は、一般的に上の方が読みやすいとされています。

条件式には以下の指針が存在する。

条件式 左側条件式 右側
「調査対象」の式。変化するもの「比較対象」の式。あまり変化しないもの

if/else 文の並び順

  • 条件は否定形より肯定系を使う。例えば、if (!debug) ではなく if (debug)
  • 単純な条件を先に書く
  • 関心を引く条件や目立つ条件は先に書く

三項演算子

行が短くなるというメリットはありますが、読みにくかったりデバッガでステップ実行できなくなるというデメリットがあります。

三項演算子を使用可能かどうかはケースバイケースで、その指針は以下。

  • 行数を短くするよりも、他の人が理解するのにかかる時間を短くする
  • 基本的には if~else を使用する。三項演算子で簡潔になるときだけ使用する

do~while ループは避ける

コードブロックを再実行する条件式が下にあり、下から上に読んでいくことになるため、普通の条件式とは異なり読みにくいです。while ループで実現すべきなのです。

関数から早く返す

return 文は積極的に使用します。早めに return することで「ガード節」をつくります。

ネストを浅くする

  • ネストが深いと、常に条件式を意識しないといけなくなる。ネストが増えるたびにコードを追うのに集中力が必要になる
  • 返り値は早めに返す
  • スレッド、シグナル、割り込みハンドラ、例外、関数ポインタ、無名関数、仮想メソッドはコードを追うのが難しくなるため、このようなコードが全体の割合を占めないように注意する必要がある(これらはコードが読みやすくなったり、冗長性が低くなったりするメリットがある)

8章 巨大な式を分割する

説明変数を用いて分割する

式を簡単に分割するには、式の意味を説明してくれる「説明変数」を用います。

要約変数を用いて分割する

大きなコードの塊を小さな名前に置き換えておくことで、コードの管理や把握を簡単にできる。これを「要約変数」と呼びます。

短絡評価の悪用

「頭がいい」コードに気をつける。あとで他のメンバーがコードを読む時に分かりにくくなります。

以下のコードは動作的には同じものですが、上の方は一度立ち止まって考えないといけなくなります。

9章 変数と読みやすさ

変数を適当に使うと以下のような問題がありプログラムが読みにくくなります。

  • 変数が多いと変数を追跡するのが難しくなる
  • 変数のスコープが大きいとスコープを把握数する時間が長くなる
  • 変数が頻繁に変更されると現在の値を把握するのが難しくなる

中間結果を削除する

以下の index_to_remove は中間結果を保持するための変数であり、これを使わなくても同じ事が実現できます。タスクはできるだけ早く完了する方が良いです。

制御フロー変数を削除する

本書では以下の done のような変数を「制御フロー変数」と呼んでいます。

制御フロー変数は、プログラムを制御するための変数であり、実際のプログラムに関係のあるデータは含まれていません。

こういった変数はうまくプログラミングすれば削除することができます。

変数のスコープを縮める

  • グローバル変数はできるだけ避ける。これはプログラマの間では認知されている
  • 変数のスコープはできるだけ縮める(「変数を追うために読むコード」が少なくなる)
  • 大きなクラスは分割して小さなクラスごとにまとめられないか考える
  • メンバ変数はできるだけローカル変数に変更する
  • クラスのメンバ変数へのアクセスを減らす方法として、メソッドをできるだけ static なものにする

定義の位置を下げる

基本的には変数は使う「直前」に定義したほうが良いです。変数の定義が早すぎると、変数を覚えておきながらコードの読み書きをしないといけなくなります。最初から全ての変数を知る必要はありません。

変数は一度だけ書き込む

変数を操作する場所が増えると現在値の判断が難しくなります。逆に永続的に変更されない変数は扱いやすい不変的な変数の場合は、const(C++) や final(Java) などのイミュータブルなものにする。

10章 無関係の下位問題を抽出する

プロジェクト固有のコードから汎用コードを分離することで、プロジェクトから切り離された境界線上の業務固有の問題に集中できます。

例えば「与えられた地点から最も近い場所を見つける」処理があったとすると、処理を「2つの地点から距離を計算する」部分と「値の簡単な操作と入出力」部分に分けることができます。

汎用コードはプロジェクトから完全に切り離されているため、開発もテストもしやすいです。

11章 一度にひとつのことを

一度に複数のことをするコードは理解しにくいです。コードをできるだけ異なる関数やクラスに分割する。

12章 コードに思いをこめる

コードは「ロジックを説明する文章」になっていると分かりやすいです。コードは読み物で、コードを読むことはエンジニアが最も多くの時間を費やす時間。

13章 短いコードを書く

最も読みやすいコードは何も書かれていないコードです。また、コードをできるだけ小さく保つことはプロジェクトが進むにつれてその恩恵は大きくなります。

  • 汎用的な「ユーティリティ」コードを作って重複コードを削除する
  • 過剰な機能は持たせない
  • 未使用のコードや不要なファイルなどは削除する
  • 標準ライブラリで使えそうなものを確認する
  • 最も簡単に問題を解決できそうな要求を考える

冒険、興奮、ジェダイはそんなものを求めてはおらん。 – ヨーダ(スターウォーズ)

14章 テストと読みやすさ

テストを読みやすくするということは、テスト以外のコードを読みやすくすることと同じくらい大切なことです。

読みにくい(扱いづらい)テストは以下のような弊害をもたらします。

  • テストを修正したくないがために、本物のコードを修正しない
  • 新しいコードを追加した時にテストを書かなくなる

テストに優しい開発

まず、テストしやすいコードとは明確なインターフェースがあります。状態や「セットアップ」がなく、検査するデータが隠されていません。

テストするコードは「テストしやすいように設計する」ように心がける。これがテストに優しい設計の鉄則です。また、あとでテストを書こうと意識しながらコード書くことも重要です。

テストのやりすぎ問題

テストは素晴らしいものですが、やりすぎは禁物。場合によってはテストに集中しすぎると以下のような問題が起きます。

  • テストのために本物のコードの読みやすさを犠牲にしてしまう。本物のコード、テストコード両者に利点がないといけない。本物のコードは単純で疎結合なもの、テストコードは読み書きしやすいものを意識する
  • テストカバレッジを100%にしないと気が済まない。90%付近からユーザーインターフェースやどうでもいいエラーケースが含まれていることが多い。現実的にはテストカバレッジが100%になることはない
  • テストがプロジェクト開発の邪魔になる。プロジェクトの一部に過ぎないテストが、プロジェクト開発の全体を支配しているような状況 のこと。エンジニアリングの時間を犠牲にしてまで書かなくてはいけないテストなのか考える必要がある

おわり

“コードは読み物”“読み手への配慮” この2つを意識すると、コードの質は飛躍的に向上することが分かりました。実務でもこの辺りを意識してハッピーなプログラマー人生にしていきたいです。

本書は「読み物としてのコード」をどう構築していくかということの、基本的な考え方や実践方法が学べます。

まだ読んでいない方はぜひ一度手にとってみてください。

ABOUT ME
maechan
ベンチャー、フリーランス、スタートアップを経験。 開発業務、人事業務に従事していました。 現在は農業系スタートアップ企業でエンジニアとして働いています。 リモートワークをしているノマドサラリーマンです。茶道とワークアウトが趣味です。
こんな記事もおすすめ

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です