リーダブルコード
名著と言われており、多くのサイトで取り上げられています。
わかりやすいコードを書くための手法が数多く紹介されており、現場でコーディングするにあたって必要な知識が詰め込まれています。
そんな本を新卒エンジニアである私が読んでみて特に重要だと思った箇所をピックアップして整理してみました。
1章 理解しやすいコード
優れたコードとはかっこいいコードや短く表現されたコードではなく、理解しやすいコードを指す。
誰かが自分のコードを見た時に、いかに短い時間で理解できるかが重要。
コードを書くときは常に 「このコードは理解しやすいだろうか?」 を自問自答することが大切になってくる。
2章 名前に情報を詰め込む
名前は短いコメントのようなもので、情報を詰め込むことが大事。
短くても読み手に伝わる情報が入ってればOK。
2.1 明確な単語を選ぶ
空虚な単語は避けよう。例えば関数名getPage
は良くない命名であると言える。「get」という単語だと、ページをどこから取ってくるのかが分からない。
インターネットから取得するならdownloadPage
とした方が伝わりやすい。
表現で迷ったときはより処理内容が伝わりやすい言い換えを調べて見ると良い。
2.2 tmpやretvalなどの汎用的な名前を避ける
当書では、いい名前を 「変数の目的や値を表すもの」 と定義している。
良くないコードとして以下のような例が紹介されている。
$tmp = $user->name;
$tmp += '' + $user->phone_number;
$tmp += '' + $user->email;
$template->set('user_info', $tmp)
この場合、$tmp
は$user_info
とすることでより分かりやすくなる。
一時的に値を補完するような変数の場合は、他に役割がないという意味が伝わるため「tmp」を使っても良いが、
他の関数で使われたり、何度も書き換えられたりする変数には明確な単語を使って命名する必要がある 。
for文で見かけるi
はインデックスやイテレータの意味を指すため、基本的にはそのままで良い。
しかし、for文がいくつもネストしている場合には、members_i
やusers_i
のように説明を補完する単語を付け加えることでより分かりやすくなる。
2.4 名前に情報を追加する
単位や重要な属性を変数名に付け加えることでより明確な名前になる場合がある。
時間を表す変数には、単位を表すh
やmin
などを追加してあげると良い。
その他、ファイルサイズ等の単位でも同じことが言えるだろう。
2.5 名前の長さを決める
わかりやすくするためにどんな場面でも長い名前をつけようとするのは良くない。
名前の長さで迷った時はスコープの大きさを参考にすると良い 。
スコープが小さく、役割が明確な場合は短い名前でも良い。
数行に収まっているif文で一時的な保管場所としての役割を持つ変数に長い名前は必要ない。
しかし、スコープが数画面に及ぶ変数にはできるだけ情報を詰め込むべきで、必要に応じて長い名前をつけるべきだ。
4章 美しさ
当書では、美しいソースコードを書くために以下の3原則が示されている。
・読み手が慣れているパターンと一貫性のあるレイアウトを使う。
・似ているコードは似ているように見せる。
・関連するコードをまとめてブロックにする。
1つ目、2つ目に関しては、同じような処理が複数ある場合は、空行を使って縦の列を揃える、改行位置を揃える、並び順を揃える、といったことを意識してみると良い。
3つ目に関しては、コードを論理的なブロックに分けて、段落を作ることを意識してみる良い。
しかし、上記で紹介したような手法は個人の好みに依存するため、プロジェクトの規約に従うことが最優先になる。ソースコードの一貫性を保つことが最も大事である。
5章 コメントすべきことを知る
当書によれば、コメントの目的は 「書き手の意図を読み手に伝えること」 だ。
コメントを適切に書くためには、不要なコメントを書かないことも大事である。
不要なコメント
・どのように動くかわかるコード
// 商品を取得する
$product = Product::find($id);
このように一目で内容が分かるコードへのコメントは不要である。
命名が不適切なためにわかりづらい関数を捕捉するようなコメントも不要である。その場合はわかりやすい名前に変更することをまずは検討してみると良い。
必要なコメント
・自分の考えを記録する
例1:// この処理は共通化した方が良いかもしれない
例2:// このクラスは肥大化しているため今後整理が必要
// サブクラス〇〇を作って分割したい
このような欠陥を認めるコメントがあることで修正が必要だということが分かる。このように処理に直接関係がなくても、考えや意図をコメントすることは重要である。
他にも、 クラスやファイルには全体像がわかるようなコメント、つまづきそうな部分には気を付けてほしいポイントのコメント をすることが重要である。
7章 制御フローを読みやすくする
if/elseブロックの並び順
// 例1:
if ($a === $b) {
// 第一のケース
} else {
// 第二のケース
}
// 例2:
if ($a != $b) {
// 第二のケース
} else {
// 第一のケース
}
例1と例2は同じ処理をするが、以下のルールを意識して意図的に使い分けると良い。
・条件は否定系よりも肯定系を使う。
・単純な条件を先に書く。
・関心を引く条件や重要な条件を先に書く。
状況によっては否定系を先に持ってきても良い。
7.7 ネストを浅くする
例えば、if文でネストが深くなると、複数の条件式を頭にいれて処理を追跡しないといけないため、非常に理解しにくいコードになってしまう。
そんなときは、失敗ケースを早めに関数からreturnすることを意識すると良い。
8章 巨大な式を分割する
8.1 説明変数
// 説明変数がない場合
if (expload(',', $users_name_str)[0] === 'root') {
}
// 説明変数がある場合
$user_name = expload(',', $users_name_str)[0];
if ($user_name === 'root') {
}
説明変数がある方がすっきりと表現されており理解までに時間がかからない。
また、expload(',', $users_name_str)[0]
を色んな箇所で使う場合その都度書くわけにもいかない。変数にしてしまうことで視覚的に分かりやすくなるだけでなく、補完を効かせて一発で入力できるようになる。
9章 変数と読みやすさ
9.1 変数を削除する
説明変数が便利であることは紹介したが、変数を定義することで簡潔さを損なってしまう場合がある。
$none = null;
if ($my_favorite->fruit === $none) {
}
このコードの良くない点は、「より明確になっていない」「新しい情報が得られるわけではない」ことだろう。
このような不要なコメントは削除するべきである。
9.2 変数のスコープを縮める
グローバル変数はどこで参照されているかを把握するのが難しい。
できる限りプライベートにして、数行のコード内で使われるように調整すべきだろう。
プライベートな変数であれば、特定のスコープでしか使用されないことを読み手に伝えることができる。
また、一つの変数に何度も別の値を代入することも避けるべきである。追跡が困難になるからだ。
10章 無関係の下位問題を抽出する。
大きなコードは小さい単位に分割すべきである。
例えば、大きな関数A内でその関数の目的からは外れる処理を行う必要がある場合、その部分を別関数Bとして切り出し、AからBを呼ぶようにすれば良い。
そうすることで読み手は関数の目的を見失わずに読み進めることができる。また、関数を分割することでテストが容易になったり、欠陥箇所を見つけやすくなる。
考え方としては以下の通りだ。
1.関数やコードブロックを見て「このコードの高レベルの目標は何か?」と自問する。
2.コードの各行に対して「高レベルの目標に直接的に効果があるのか? あるいは、無関係の下位問題を解決しているのか?」と自問する。
3.無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。
感想
当書を読み終えると、ある程度根拠を持ってコードを書けるようになるのではないかと思います。
読んでいる時は「なるほど」と思うのですがいざ実践するとなると難しいです。
まだまだ実践できてない部分もあるので、今後も当書にはお世話になることと思います。