【書籍】リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック
はじめに
奇麗なコードを書きたい!!!
常日頃から思っている事なのですが、メソッド名や関数名、変数名を記述する時やリファクタリングをするのが、あまり得意ではありません。そんな中、奇麗なコードを記述する友人に勧められて「リーダブルコード」を読んでみました。
今回は勉強になった事をメモとしてまとめ、実践した事や感じた事をブログに投稿させていただきます。
至らない点もあるかと思いますが、ご意見・ご感想をいただけると嬉しいです。
はじめに(メモ)
・「読みやすい」コードを書くのに「面白い」ことをする必要はない、良い名前をつける、適切なコメントを書く
意味のある単位に分割する。綺麗に整形する。こうした基本的なことを着実にやる事が重要です。
・「読みやすい」コードを書くことは、「理解しやすい」コードを書くことであり、その結果として「優れた」コードにつながります。
はじめに(感想)
・「読みやすい」コードを書くことは、「理解しやすい」コードを書くことであり、その結果として「優れた」コードにつながります。
はじめから耳が痛いなと思いました。読みやすさが理解しやすさとなり優れたコードとなる。その事を意識して読みやすさにこだわります。
第一章(メモ)
・コードは理解しやすくなければいけない
具体的に言えば、誰かが君のコードを読んで理解する時間を最短にするという事です。
・コードは短くした方がいい
だけど、「理解するまでにかかる時間」を短くする方が大切です。
・常に一歩下がって「このコードは理解しやすいだろうか?」と自問自答してみる事が大切です。
理解しやすいコードになってから、次のコードを書き始める事が大切です。
第一章(感想)
・誰かが君のコードを読んで理解する時間を最短にするという事です。
今回の案件でこの事が出来ていないと思っていて、読みにくいコードを書いてしまっていたなと反省しました。第三の者の事を意識してコードを書く意識を持ちます。
・常に一歩下がって「このコードは理解しやすいだろうか?」と自問自答してみる事が大切です。
理解しやすいコードになってから、次のコードを書き始める事が大切です。
問題を解くロジックを考えてから、そのロジックのコードが理解しやすいかを考えてからコードを書きます。
第二章(メモ)
・名前の付け方
1.明確な単語を選ぶーGetではなく、状況に応じてFetchやDownloadなどを使う。
2.汎用的な名前を避ける(あるいは使う状況を選ぶ)ー明確な理由があれば良い
3.抽象的な名前よりも具体的な名前を使う
4.接尾辞や接頭辞を使って情報を追加するーミリ秒を表す変数名には、後ろにmsを付ける。
5.名前の長さを決める
6.名前のフォーマットで情報を伝える
・気取った言い回しよりも明確で正確な方が良いです。
・いい名前というのは変数の目的や値を表すものです。
・tmpというという名前は、生存期間が短くて、一時的な保管が最も大切な変数にだけ使います。
・変数や関数などの構成要素の名前は、抽象的ではなく具体的なものにします。
・絶対に知らせなきゃいけない大切な情報があれば、「単語」を変数名に追加すれば良いです。
・プロジェクト固有の省略形はNGです。
第二章(感想)
3.抽象的な名前よりも具体的な名前を使う。
少し長くなったとしても英語で具体的に名前を付けるように意識します。
第三章(メモ)
・誤解される名前に気をつけましょう。
名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する事が大切です。
・限界値を明確にするには、名前の前にmax_やmin_付けることが大切です。
例:
CART_TOO_BIG_LIMIT ×
MIN_ITEMS_IN_CART
・ブール値の変数やブール値を返す関数の名前を選ぶときには、trueとfalseの意味を明確にしないといけないです。
例:
bool read_password = true;
①パスワードをこれから読み取る必要がある?
②パスワードをすでに読み取っている?
・名前を否定系ではなく、肯定系にした方が声に出して読みやすく、短くて済みます。
例:
bool disable_ssl = false; ×
bool use_ssl = true
第三章(感想)
・誤解される名前に気をつけましょう。
他の意味に捉えられそうな名前だと思ったら、別の言い方や単語が使えないか一歩引いて考えます。
第四章(メモ)
・優れたソースコードは「目に優しい」ものでなければいけないです。
1.読み手が慣れているパターンと一貫性のあるレイアウトを使う
2.似ているコードは似ているように見せる。
3.関連するコードをまとめてブロックにする。
・美しさと優れた設計は独立した考えだと思っている。できればその両方を追求してもらいたいです。
・プログラミングの時間のほとんどはコードを読む時間です。
・コードの並びがコードの正しさに影響を及ぼすことは少ないです。
どんな順番で並べてもいいが、意味のある順番に並べると良いです。
1.対応するHTMLフォームの<input>フィールドと同じ並び順にする。
2.「最重要」なものから重要度順に並べる
3.アルファベット順に並べる
・人間の脳はグループや階層を一つの単位として考えます。
・文章と同じで、コードも「段落」に分けるべきです。
・下記例のどちらを選んでも、コードの読みやすさに大きな影響はない。でも、この2つのスタイルを混ぜてしまうと、すごく読みにくいものになってしまいます。
例:
class Logger{
};
class Logger
{
};
・一貫性のあるスタイルは「正しい」スタイルよりも大切です。
第四章(感想)
・美しさと優れた設計は独立した考えだと思っている。できればその両方を追求してもらいたいです。
細かい事ですが、余白だったり例にも記述している{};等を統一して奇麗にコードを書くように心がけます。C#の研修でリーダーしていた人は{}の書き方を凄く気にされていたことを思い出しました。自分も意識して美しいコードを書くように気を付けます。
第五章(メモ)
・コメントの目的は、書き手の意図を読み手に知らせる事です。
・コードからすぐに分かる事はコメントに書いてはいけないです。
・ひどい名前はコメントをつけずに名前を変える事が重要です。
優れたコメントよりも名前の方が重要です。
優れたコード > ひどいコード + 優れたコメント
・優れたコメントとは「考えを記録する」ためのものです。
コードを書いているときに持っている「大切な考え」のことです。
・コードの欠陥にコメントをつける事が大切です。
これからコードをどうしたいのかを自由にコメントに書く事が大切です。
そのコメントを書く事で、コードの品質や状態を知らせたり、改善の方向を示したり出来ます。
・定数には定数の値にまつわる「背景」についてコメントを付ける事が大切です。
例:image_quality = 0.72; /0.72ならユーザはファイルサイズと品質の面で妥協できる。
・他の人に質問されそうなことを想像し、読み手の立場になって考える事が大切です。
・関数やクラスを文章化するときには「このコードを見てビックリすることは何だろう?どんなふうに間違えて使う可能性があるだろう?」と自分に問いかける事が大切です。
・プログラマの多くはコメントを書きたがらない、自分の思っていることをとりあえず書き出してみる事が大切です。
例:「ヤバい。これはリストに重複があったら面倒な事になる」
1.頭の中にあるコメントをとにかく書き出す。
2.コメントを読んで改善が必要なものを見つける。
3.改善する。
第五章(感想)
・コードからすぐに分かる事はコメントに書いてはいけないです。
今回の案件でコード読めば分かるのでメモをあまり書かなかったのですが、何日か経過した後に同じコードを読むと理解に苦しみました。
リーダーのコードを読んでみると細かく丁寧にメモが書かれていたので、見習って明らかに読めば分かるコード以外には細かく仕様等をコメントに残しておこうと思っています。
第六章(メモ)
・コメントは領域に対する情報の比率が高くなければいけないです。
・複数のものを指す可能性がある「それ」や「これ」などの代名詞を避ける事が大切です。
・よくわからない引数にはインラインコメントを使う事が大切です。
第六章(感想)
・よくわからない引数にはインラインコメントを使う事が大切です。
例:
SendEmail(
"user@example.com", // 宛先メールアドレス
true, // HTML形式で送信するか
false, // 重要フラグ(緊急かどうか)
3 // 再送回数
);
インラインコメントをもっと記述しておけば読みやすかったコードが沢山あるなと思いました。
既存システムに合わせないといけない場合はインラインコメントを書いてしまうと美しさが損なわれてしまう可能性があるので、一から開発する機会があれば、インラインコメントで統一しても良いかと思いました。
第七章(メモ)
・条件やループなどの制御フローはできるだけ「自然」にする。コードの読み手が立ち止まったり読み返したりしないように書く事が大切です。
・条件式の引数の並び順
例:if(length >= 10)
1.左側(length)「調査対象」の式。変化する。
2.右側(10)「比較対象」の式。あまり変化しない。
if(length >= 10) 読みやすい
if(10 >= length) 読みにくい
・条件は否定系よりも肯定系を使う。
例:if(debug){}:OK、if(!debug){}:NG
第七章(感想)
・条件は否定系よりも肯定系を使う。
今回の案件で否定形が多用されていて読みにくいと思っていたことがあります。
次回からは、なるべく否定形ではなく肯定系でプログラム出来ないか考えて記述します。
第八章(メモ)
・巨大な式は飲み込みやすい大きさに分割する事が大切です。
・説明変数(式の意味を説明してくれるコード)
例:if line.split(':'[0].strip() == "root"; NG
username = line.split(':'[0].strip(); OK
if username == "root"
・要約変数(大きなコードの塊を小さな名前に置き換えて、管理や把握を簡単にする変数)
式を説明する必要がない場合でも、式を変数に代入しておくと便利です。
例:
if (request.user.id == document.owner_id) {
// Onwerの場合
}
...
if (request.user.id != document.owner_id) {
// Ownerでない場合
}
NG
final boolean user_owns_document = (request.user.id == document.owner_id);
if (user_owns_document) {
// Onwerの場合
}
...
if (!user_owns_document) {
// Ownerでない場合
}
OK
第八章(感想)
・巨大な式は飲み込みやすい大きさに分割する事が大切です。
説明変数や要約変数を使用して巨大な式を分割するイメージがあまり沸いていないのすが
基本的に巨大な式は極力さけて、分割してコードを書くように心がけます。
第九章(メモ)
・変数を適当に使うとプログラムが理解しにくくなります。
1.変数が多いと変数を追跡するのが難しくなる。
2.変数のスコープが大きいとスコープを把握する時間が長くなる。
3.変数が頻繁に変更されると現在の値を把握するのが難しくなる。
・グローバル変数は避ける事が大切です。
どこでどのように使われるのかを追跡するのが難しい
また、「名前空間を汚染する」(ローカル変数と衝突する可能性がある)
グローバル変数に限らず、全ての変数の「スコープを縮める」のはいい考えです。
・変数のことが見えるコード行数をできるだけ減らす事が大切です。
・変数は一度だけ書き込みます。
「永続的に変更されない」変数は扱いやすいです。
第九章(感想)
・グローバル変数は避ける事が大切です。
今回の案件でグローバル変数を多用してしまいました、、
確かにグローバル変数を多用してしまうとスコープの概念から外れるので
追跡する事が難しくなるなと思いました。
次回からはスコープ内で完結できるコードを記述します。
第十章(メモ)
・エンジニアリングとは、大きな問題を小さな問題に分割して、それぞれの解決策を
組み立てることです。
・無関係の下位問題を積極的に見つけて抽出する事が大切です。
1.関数やコードブロックを見て「このコードの高レベルの目標は何か?」と自問する。
2.コードの各行に対して「高レベルの目標に直接的に効果があるのか?あるいは無関係の下位問題を解決しているのか?」と自問する。
3.無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数になる。
・複数のプロジェクトで再利用できる汎用コードは、簡単に共有できるように特別なディレクトリ(例:util/)を用意します。
・プロジェクト固有のコードから汎用コードを分離する事が大切です。
ほとんどのコードは汎用化出来ます。一般的な問題を解決するライブラリやヘルパー関数を作っていけば、プログラムに固有の小さな核だけが残ります。
第十章(感想)
・無関係の下位問題を積極的に見つけて抽出する事が大切です。
コードの高レベルの目標を立てる事、直接的に効果があるのかを自問する事、無関係のコードを解決しているコードを抽出して別の関数にする事、汎用コードは特別なディレクトリに纏める等、授業では教わらなかった重要な事を学習する事が出来ました。
特に目標を立てる事と効果があるのかを自問する事は今後実装する時に意識します。
第十一章(メモ)
・一度に複数のことをするコードは理解しにくい
コードは一つずつタスクを行うようにします。
・読みにくいコードがあれば、そこで行われているタスクを全て列挙する。そこには別の関数(やクラス)に分割できるタスクがあるだろう。それ以外は、関数の論理歴な「段落」になるタスクをどのように分割するかよりも、分割するという事が大切です。
・一番難しいのはプログラムが行なっていることを正確に説明する事です。
第十一章(感想)
・一番難しいのはプログラムが行なっていることを正確に説明する事です。
第三者の人が聞いた時に正しく理解出来るかを意識して、コードを記述します。
第十二章(メモ)
・誰かに複雑な考えを伝えるときには、細かいことまで話しすぎると相手を混乱させてしまう。自分よりも知識が少ない人が理解できるような「簡単な言葉」で説明する能力が大切です。
自分の考えを凝縮して、最も大切な概念にする事が必要になります。
・コードも「簡単な言葉で」書くべき
コードを明確にする簡単な手順
1.コードの動作を簡単な言葉で同僚にもわかるように説明する。
2.その説明の中で使っているキーワードやフレーズに注目する。
3.その説明に合わせてコードを書く
・問題や設計をうまく言葉で説明できないのであれば、何かを見落としているか、詳細が明確になっていないという事です。プログラム(あるいは自分の考え)を言葉にすることで明確な形になります。
第十二章(感想)
・誰かに複雑な考えを伝えるときには、細かいことまで話しすぎると相手を混乱させてしまう。自分よりも知識が少ない人が理解できるような「簡単な言葉」で説明する能力が大切です。
難しい単語を極力使わずに、使ったとしても理解出来るように噛み砕いてから説明するように心がけます。
第十三章(メモ)
・プロジェクトを開始するときには、これから実装するカッコいい機能のことを考えて興奮するものだ。
そして、プロジェクトに欠かせない機能を過剰に見積もってしまう。その結果、多くの機能が完成しないか、全く使われないか、アプリケーションを複雑にするものになってしまいます。
・コードをできるだけ小さく軽量に維持する事が大切です。
・未使用のコードを削除する事が大切です。
・プログラマというのは、既存のライブラリで問題を解決できることを知らない事が多いです。
たまにはライブラリの全ての関数・モジュール・型の名前を15分かけて読んでみよう。
・平均的なソフトウェアエンジニアが一日に書く出荷用のコードは10行なのだそうです。
第十三章(感想)
・未使用のコードを削除する事が大切です。
当たり前の事なのですが、何か起きた時に残しておきたいと思っていて、使わないコードを残していたのですが、同期の出来るエンジニアは使わないコードは直ぐに消していたので、次回からは気を付けます。
第十四章(メモ)
・テストコードを読みやすくするのは、テスト以外のコードを読みやすくするのと同じくらい大切なことです。
・一般的な設計原則として「大切ではない詳細はユーザから隠し、大切な詳細は目立つようにする」べきです。
第十四章(感想)
・一般的な設計原則として「大切ではない詳細はユーザから隠し、大切な詳細は目立つようにする」べきです。
次回から設計について学習しようと思っているのですが、この原理を覚えておき、設計する時に意識しようと思います。
最後に
リーダブルコードを読んでから自分の意識が変わりました。
読みやすさと理解しやすさを意識し、第三者の人が見た時に分かりやすいコードを書くようにしています。
奇麗なコードを書きたいと少しでも思っている人は全員読む事をお勧めします。
Discussion