リーダブルコード
基本定理
コードは他の人が最短時間で理解できるように書く。「コードの量」ではなく「理解にかかる時間」を最小にする。
短いコードを書く
要求を詳しく調べれば、問題をもっと簡単にできる。 そうすれば必要なコードは少なくなる。往々にして、プロジェクトに欠かせない機能は過剰に見積もられてしまう。その結果、多くの機能が完成しないか、全く使われないか、アプリケーションを複雑にする。 プログラマというのは、実装にかかる労力を過小評価するもの。実装にかかる時間を楽観的に見積もったり、将来的に必要となる保守や文章化などの「負担」時間を忘れたりする。
新しいコードを書かない
- 要求を削除する
- 問題を簡単にする
- 標準ライブラリを使う
簡潔なコードを書くのに欠かせないのは、ライブラリが何を提供してくれているかを知ること
軽量なコードを維持する
- 重複コードを削除する
- 未使用コードや無用機能を削除する
名前
最善の名前とは、誤解されない名前である。
いい名前
- 目的や値を表す
- 抽象的ではなく具体的
- 「単語」として大切な情報を含む
- 単位を含む
Tips
- プロジェクト固有の省略形はダメ
- スコープが小さければ、情報を詰め込む必要はない
- エンティティ(変数、クラス、メンバ変数、定数)ごとに異なるフォーマット(アンダースコア・ダッシュ・大文字)を使う
- ブール値の変数名には、頭にis・has・can・shouldなどをつける
- 否定形は避ける
get
は「軽量アクセサ」のみ許される- 直行する概念は、無理にまとめず別々に使えるようにする
- イテレータが複数あるときは、明確な名前をつける
コメント
記録すべき自分の考え
- なぜコードが他のやり方ではなくこうなったのか
- コードの欠陥
- 背景
実例を使う
すべての機能を「見せる」
// 実例: Strip("abba/a/ba", "ab") は"/a/"を返す
String Strip(String str, String chars) { ... }
Tips
- コードからすぐに分かることをコメントに書かない
- ひどい名前はコメントをつけずに名前を変える
- 「ライターズ・ブロック」を乗り越えるには、とにかく書き始めるしかない
- これからコードをどうしたいのか、自由にコメントを書く
- 全体像を理解できるコメント書く
新しいチームメンバーにとって、最も難しいのは「全体像」の理解
変数
説明変数
式を表す変数(式の分割)
before
if line.split(":")[0].strip() == "root":
after
username = line.split(":")[0].strip()
if username == "root":
要約変数
管理や把握を簡単にする変数(大きなコードの塊を小さな名前に置き換える)
before
if (request.user.id == document.owner.id) { ... }
if (request.user.id != document.owner.id) { ... }
after
final boolean user_owns_document = (request.user.id == document.owner.id)
if (user_owns_document) { ... }
if (!user_owns_document) { ... }
変数の削除
- コードが読みやすくならない変数は削除する
- 制御フロー変数を削除する
- タスクをできるだけ早く完了する(早期return)
その他
- すべての変数の「スコープを縮める」のはいい考え
- イミュータブルはトラブルになる傾向が少ない
制御フロー
「ガード節」を使い、 ネストは避ける。
条件式の引数の並び順
- 左側 調査対象の式(変化する)
- 右側 比較対象の式(変化しない)
if/elseブロックの並び順
- 条件は肯定形を使う
- 単純な条件を先に書く
- 関心を引く条件や目立つ条件を先に書く
テスト
新しいテストの追加や修正を簡単にすることが大切。テストは、「こういう状況と入力から、こういう振る舞いと出力を期待する」のレベルまで要約できる。
優れたテストの書き方
- テストが何をしているのか、1つの文で記述する
- 役立つエラーメッセージを出力する
- 適度にテストが分割されている
- 極端な入力値を使ってテストする
テスト容易性と設計
テスト容易性の低いコード
特性 | テスト容易性の問題 | 設計の問題 |
---|---|---|
グローバル変数 | テストごとに初期化する必要がある | 関数にどんな副作用があるのかわかりにくい |
多くの外部コンポーネントに依存 | 最初に足場を設定しなければいけないので、テストを書くのが難しい | 任意の変更にどんな影響があるのかを理解するのが難しい等 |
コードが非決定的な動作 | テストは当てにならず、信頼できない | プログラムを論理的に判断できなくなる等 |
テスト容易性の高いコード
特性 | テスト容易性の利点 | 設計の利点 |
---|---|---|
クラスが小さい | テストするのにセットアップがあまり必要にならない | 状態の少ないクラスは単純で理解しやすい |
クラス・関数が1つのことをしている | テストケースが少なくて済む | システムが疎結合である |
他のクラスにあまり依存していない | 各クラスは独立してテストできる | クラスは他の部分を気にすることなく簡単に修正や削除ができる |
インターフェースが明確 | 明確な動作をテストできる | 再利用しやすい |
その他
スタイル
コードの「見た目」をよくすれば、コードの構造も改善できる。ただし、一貫性のあるスタイルは、「正しい」スタイルよりも大切。
- 似ているコードは似ているように見せる
- 重複を排除するとコードは簡潔になる
- 意味のある順番にコードを並べる
- コードも段落で分ける
関数
理想とは程遠いインターフェースに妥協しない。エンジニアリングとは、大きな問題を小さな問題に分割して、それぞれの解決策を組み立てることに他ならない。
- プロジェクト固有コードから汎用コードを分離する
- 小さな関数を作りすぎると、逆に読みにくくなってしまう
- 「一度に1つのタスク」を適用する
その他
- 読みにくいコードがあれば、まずはそこで行われているタスクをすべて列挙する。そこには別の関数(やクラス)に分割できるタスクがある
- プログラムを簡単な言葉で説明する。説明することでコードがより自然になっていく