リーダブルコード 個人的重要箇所
理解しやすいコード
コードは理解しやすくなければいけない
コードの簡潔と安心では、安心を選ぶ。
コードは最短時間で他の人が理解できるようにかかなければならない
コードは短くしたほうがいいけれど、理解するまでにかかる時間を短くするほうが大事。
他人がコードを理解できないだけでなく、半年後の自分が理解できなくなるかもしれない。
表面上の改善
名前に情報を詰め込む
名前に情報を詰め込む
sizeやgetなどの名前は一見問題なさそうに見えるが、情報量が含まれていないこともあるため気をつけるようにする。そのために
- 明確な単語を選ぶ
- 汎用的な名前を避ける(あるいは使う状況を選ぶ)
- 抽象的な名前よりも具体的な名前を使う
- 接尾辞や接頭辞を使って情報を追加する
- 名前の長さを決める
- 名前のフォーマットで情報を伝える
等の工夫をする。
イテレーターの名前をつける際に、配列の名前と最初の文字にするとバグに気づきやすくなる。
例) clubs[ci], members[mi], users[ui], clubs[clubs_i], members[members_i], users[users_i]など。
直行する概念は無理に一つにしようとせずに、別々に使えるようにする。そうしないと名前がややこしくなってしまう。例) 無理にコマンド一つにまとめようとせず、--use_local_databaseのようなオプションを用意する。
すべての変数名に属性を入れるのではなく、変数の意味を間違えて使ってしまったときにバグになりそうなところにunescapedなどの属性を変数名に入れるようにする。
識別子のスコープが大きいときは変数名がなにであるのか情報が近くに含まれていないため、明確にわかるような名前をつけるようにする。
誤解されない名前
名前が他の名前と間違えられることはないだろうか?と何度も自問自答する。
filterという名前を例に取った場合、それは選択するのか、除外するのかがわからないため、select、exclude等の名前を付けて明確にする。
ブール値の変数名はis、has、can、shouldのような名前をつけてわかりやすくすることが多い. 。user_is_autheticatedなど。
getなどの名前はユーザーにとって軽量アクセサという認識がある。取ってくるデータが多い場合にはcompute等の名前をつけ、大量のデータを持ってくる処理だということを明確にする。
美しさ
コードを読みやすくするため三原則
- 読み手が慣れているパターンと一貫性のあるレイアウトを使う
- 似ているコードは似ているように見せる
- 関連するコードをまとめてブロックにする
リーダブルコード作者は美しさと優れた設計を独立した考えだとしている。できれば、その両方を読者には追求してほしい。
同じようなコメントが三回以上続いてしまった場合などは、関数の構造を模してコメントを付けたものをそれぞれの関数の一番上に置く。そうすることで、可読性も上がりコメントを書く量が減る。
コードの表面上の改善はコードの構造も改善できる。
HTMLのタグの順番を対応した並び順、重要度順、アルファベット順などコードの中で一連の並び順を使うべきである。
コードを段落でわけることでざっと目を通せるようになる。短い段落なのか、長い段落7日は最終的には個人の好みになるが、チームで合わせないと読みにくくなってしまうため、揃えるようにする。
一貫性のあるスタイルは「正しい」スタイルよりも大切。
コメントすべきことを知る
コメントの目的は、書き手の意図を読み手に知らせることである。
- コメントするべきではないことを知る
- コードを書いているときの自分の考えを記録する
- 読み手の立場になって何が必要になるかを考える
コードからすぐにわかることをコメントに書かない。
改善が必要なときには
TODO: もっと高速なアルゴリズムを使う
のようなフォーマットのコメントを残す。
定数に、なぜその値なのかというコメントをつけることも多々ある。
質問されそうなことを想像する、ハマりそうな罠を告知する、要約コメントをつける等の対策を取ることで可読性が上がる。
ライターズブロックを乗り越えるにはとにかく書き始める。とりあえず書いたものを言葉を変えたりして修正することで、適切なコメントになる。
コメントは正確で簡潔に
コメントは領域に対する情報の比率が高くなければいけない
コメントを簡潔にしておく... 短いコードには3行分などの長いコメントを付けない
あいまいな代名詞を避ける... 代名詞に名詞を代入してみる
歯切れの悪い文章を磨く
関数の動作を正確に記述する
入出力のコーナーケースに実例を使う...
例) // 実例 Strip("ab", "a")はaを返す。
言葉の説明だけではわかりにくい場合があるので、実例を用いて説明することでわかりやすくなる。
コードの意図を書く
名前引数コメント... プログラム言語によっては引数に名前をつけて渡すことができるが、そのような機能がない場合にはインラインコメントをつけて対応する。
例) Connect(/timeout_ms = / 10);
情報密度の高い言葉を使う... データベースのキャッシュ層である、正規化する等の言葉で長い説明が短い言葉で済むことがある。
ループとロジックの単純化
制御フローを読みやすくする
文章で「もし君が18歳以上ならば」という文章にしたときに、変わる値(君の年齢)が先に来ていて、変わらない値(18歳以上という条件)が後に来ている。
文章が自然に成り立つように条件式のコードも合わせると読みやすくなる。
if (your_age >= 18) の並びで書く。
行数を短くするよりも、他の人が理解するのにかかる時間を短くする
do/whileループは書き直せることが多い場合には、積極的に避けるようにする。条件が前もって書かれていないため、可読性、エラーなどの問題が起きやすくなってしまう。
変更するときにはコードを新鮮な目で見る。一歩下がって全体を見る。
コードを作成していると、これが一番簡単な解だとコードを書いている側が思っていても、初めて見た人にとっては複雑に見えることがある。ネストを浅くするなどして、回避する。
巨大な式を分割する。
巨大な式は飲み込みやすい大きさに分割する。
説明変数
式を説明するために変数名を使う
要約変数
複雑なコードを簡単に説明するために変数を使う
ド・モルガンの法則を用いて、式を簡単にすることができる。
頭がいいコードに気をつける。あとで他の人がコードを読むときにわかりにくくなる。
複雑なロジックに取り掛かる際に、実現したいことの条件の反対を考えてみる。
例)1を含む、ではなく1を含まないと考える
そうすることで、条件式が簡潔になり、バグも少なくなるケースがある。
変数と読みやすさ
- 変数が多いと変数を追跡するのが難しくなる
- 変数のスコープが大きいとスコープを把握する時間が長くなる
- 変数が頻繁に変更されると現在の値を把握するのが難しくなる
説明変数や要約変数を使ってコードを読みやすくしていく。その中で読みやすくならない変数を削除する。
now = datetime.datetime.now()
root_message.last_view_time = now
の変数はあまりよくない。nowと名前をつけなくても、十分にコードから読み取りやすい程度の複雑さであるから。
中間結果を保つだけの変数は使わずに、結果を直接用いるようにしてコードを短くする。
変数のことが見えるコード行数をできるだけ減らす
最初からすべての変数のことを知る必要はないので、使用する箇所の近くで変数宣言をするようにする。
変数を操作する場所が増えると、現在地の判断が難しくなる。
まとめ
- 邪魔な変数を削除する
- 変数のスコープをできるだけ小さくする
- 一度だけ書き込む変数を使う
コードの再構成
無関係の下位問題を抽出する
エンジニアリングとは大な問題を小さな問題に分割して、それぞれの解決策を組み立てること。 この原則をコードに当てはめることで堅牢かつ読みやすいコードになる。
無関係の下位問題を積極的に見つけて積極的に抽出するために
- 関数やコードブロックを見て、このコードの高レベルの目標は何かを明らかにする
- コードの各行に対して高レベルの目標に効果があるのか、無関係の回もなぢを解決しているのかを明らかにする
- 無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。(無関係の下位問題 = プロジェクト固有ではない、汎用なコード)
これらのステップを踏む。
既存の関数等でわかりにくいインタフェースのものを使用する場合、自作でラッパー関数を作りわかりやすくする。また、既存のコードでわかりにくい箇所がある場合にはインターフェースを整えるようにする。
「無関係の下位問題」に関する関数は広く使用可能なので(util/)のようなディレクトリを用意し、そこにファイルを入れる。
まとめ プロジェクト固有のコードから汎用的なコードを切り離す。
1度に1つのことを
コードは1つずつタスクを行うようにしなければならない
一行一行のコードをタスクに分けて、デフラグをする。関数化、クラス化、コードのブロックに分けなど。
正しい分け方かどうか、よりも分けること自体が大事。if文の中が複雑な式、構造になっている場合にはタスクを分けて考え、それをコードにする。
プログラムが行っていることを正確に説明できるようにする。
コードに思いを込める
コードは簡単な言葉で書くべきである。そのために
- コードの動作を簡単な言葉で誰にでもわかるように説明する
- その説明の中で使っているキーワードやフレーズに注目する
- その説明に合わせてコードを書く
の手順を追う。
コードの動作を説明の中で出てこなかった事柄、名前から不必要な変数名などが明らかになる。明らかになった変数名は汎用的な名前にすることができ、そうすることで考えなくてはならない事柄が減り、可読性が上がる、面倒なことが減るなどのメリットがある。
これらを行う際に、ラバーダッキングが有効な手段になりえる。
短いコードを書く
最も読みやすいコードは何も書かれていないコード
すべての要件を満たそうとすると、大変な作業になる。そのソフトウェアにとって必要なものはなにかを選別し、必要なものだけを実装する。
ソフトウェアエンジニアが書く一日の平均コード量は、なんと10行。
できるだけコードを書かないようにするために、
- 不必要な機能をプロダクトから削除する。過剰な機能は持たせない。
- 最も簡単に問題を解決できるような要求を考える。
- 定期的にすべてのAPIを読んで、標準ライブラリに慣れ親しんでおく。
選抜テーマ
テストと読みやすさ
他の人が安心してテストの追加や変更ができるように、テストコードを読みやすくする。
大切ではない詳細はユーザーから隠し、大切な詳細は目立つようにするべき。
そのために、テストの内容を示したものでないどうでもいいコードは、ヘルパー関数などを作りきれいにする。テスト内容を示しているものを目立たせるようにする。
テストのトップレベルはできるだけ簡潔にする。入出力のテストはコード1行で記述できるとよい。
エラーメッセージがよりわかりやすい関数、メソッドを使うようにする。わかりやすいエラーメッセージを吐く関数を自作するのもよし。
コードを完全にテストする最も単純な入力値の組み合わせを選択しなければいけない。
テストには最もきれいで単純な値を選ぶ。
ストレステストなどテストに大量の値を入れたいときがある。そのような場合にはプログラムを組み値を渡すようにすることで、記述量が減り可読性も上がる。
コードを検証するときには完璧な入力値を1つ作るのではなく、小さなテストを複数作るほうが簡単かつ効果的かつ読みやすくなる。
テストコードは関数になっていることが多い。その際には、
- テストするクラス
- テストする関数
- テストする状況やバグ
がすぐに理解できる名前が良い。
Test_関数名_状況
の形式でテストコードの名前をつける。
ほとんどのテスティングフレームワークではテストが失敗したときにはその関数の名前が印字されるようになっている。そのため、関数名はコメントだと思ってもよい。長い名前になってしまうのは気にしなくて良い。
あとでテストを書くつもりでコードを核とテストしやすいようにコードを設計するようになる。
テスト容易性の低いコード
テスト容易性の高いコード
- クラスが小さい。あるいは内部状態を持たない。
- クラスや関数が1つのことをしている。
- クラスが他のクラスにあまり依存していない。高度に疎結合されている。
- 関数は単純でインターフェースが明確である。
やりすぎ
テストのために本物のコードの読みやすさを犠牲にしてしまってはいけない。両者に利点があるようにする。
テストのカバレッジは100%でなくてよい。そもそも現実的にカバレッジが100%になることはない。残り10%のテストはUIやどうでもいいエラーケースが含まれている。バグのコストが高くないのでテストが割に合わない。またプロダクトの種類によってテストコードにかける最適な時間は変わってくる。
テストがプロダクト開発の邪魔になってはいけない。
「分/時間カウンタ」を設計・実装する
一つの英単語で動詞と名詞が同じスペルものは、直感的に関数名などを理解できなくなる要因になってしまうので、取り扱いに注意する。他の英単語に差し替えるなど。
ユーザーフレンドリーなコードを書くために、コードの第一印象を同僚などに聞いてみる。