リーダブルコードまとめ

# リーダブルコード

数年前(プログラミング初心者の時)に読んだので、もう一度振り返りでサクッとまとめてみました。

## 1. 理解しやすいコード

> コードは理解しやすくなければならない。

**読みやすさの定理**

> コードは他の人が最短時間で理解できるように書かなければならない。

## 2. 名前に情報を詰め込む

> 名前に情報を詰め込む

tmp, size, getなどはわかりにくいので❌

### 明確な単語を選ぶ

e.g.
getPage() → downloadPage()
size() → height(), numNodes, memoryBytes()
stop() → kill()(取り消しができないほど重い操作), Pause()(後から再開できる場合)

| 単語 | 代替案 |
|:-:|:-:|
| send | deliver, dispatch, announce, distribute, route |
| find | search,extract, locate, recover |
| start | launc, create, begin, open |
| make | create, set up, build, generate, compose, add, new |

### tempやretvalなどの汎用的な名前を避ける

retvalは「これは戻り値です」以外の情報はない。

ループイテレータは、汎用的だが、`clubs[i].members[k] == users[j]` → `clubs[ci].members[mi] == users[ui]` のようにバグが分かりやすいようにする。

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

ServerCanStart() → CanListenOnPort()
DISALLOW_EVIL_CONSTRUCTORS → DISALLOW_COPY_AND_ASSIGN
--run_locally() → --extra_logging() / --use_local_database

### 名前に情報を追加する

* 単位
`string id = "af84ef845cd8"` → `string hex_id = "af84ef845cd8"`

| 関数の仮引数 | 単位を追加した仮引数 |
|:-:|:-:|
| start(int delay) | start(int delay_secs) |
| CreateCache(int size) | CreateCache(int size_mb) |
| ThrottkeDownload(float limit) | ThrottkeDownload(float max_kbps) |
| Rotate(float angle) | Rotate(float degrees_cw) |

* その他の重要な属性

| 関数の仮引数 | 単位を追加した仮引数 |
|:-:|:-:|
| プレインテキストのpassword | plaintext_password |
| 文字コードutf-8のhtml | htmx_utf8|
| 入力されたdataをURLエンコードした | data_url_enc |
| エスケープされていないコメント　 | unescaped_comment |


ハンガリアン記法 : 変数名の接頭辞に**型**をつける(e.g. pLast, psqBuffer, cch, mpcopx)

### 名前の長さを決める

* 長い名前を避ける(ダメではない)
* スコープが小さければ短くてok
* 頭文字と省略形を避ける(特にプロジェクト固有の省略形はダメ！BEManagerなど新メンバは理解できない)
* 不要な単語を捨てる(e.g. ConvertToString()→ToString())

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

* 定数 CONSTANT_NAME→kConstantName (#defineマクロと区別するため)
* メンバ変数 `val_`(アンダースコアをつける)
* jQueryのライブライ関数を代入した変数 $val ($をつける)
## 3. 誤解されない名前

> 名前が他の意味と間違えられることはないだろうか？と何度も自問自答する。

### filter

`results = data.filter("age <= 20")`とすると、resultsは20歳以下のオブジェクトか20歳以下ではないオブジェクトかわからない。→ **select()** にする。除外の場合は **exclude()** にする。

### Clip(text, lenght)

段落の内容を切り抜く関数clip(text, lenght)は以下2通りの意味で捉えられる。
* 最後からlength文字を削除する → **remove()** にする
* 最大lenght文字まで切り詰める → **truncate()** にする

また、length → max_length → max_charsにする。

### 限界値の定義

`CART_TOO_BIG_LIMIT`だと未満か以下か不明 → `MAX_ITEMS_IN_CART`にする

![](https://storage.googleapis.com/zenn-user-upload/46e324a772db-20240404.png)

### ブール値の名前

`bool read_password = true`は以下2つの解釈がある。
* パスワードをこれから読み取る必要がある
* パスワードをすでに読み取っている
→ need_password, user_is_authenticated

boolはis, has, can, shouldなどの接頭辞をつけると分かりやすい(e.g. spaceLeft()→ hasSpaceLeft())
また、名前は否定形より肯定形の方がいい(e.g. disable_ssl=false→ use_ssl=true)

### ユーザの機体に合わせる

一般的にgetやsizeは軽量なイメージ

* get()はjavaでは、メンバの値を返すだけの軽量アクセサ。コストが多い場合等はcomputeXXX()を使う
* list.size()→O(1)ではない場合などcoutSize()やcoutElementsにする。size()はO(1)

### 複数の名前を検討する

e.g. 再利用したい実験のIDの名前

* template → 曖昧。これはテンプレートか、このテンプレートを使っているわからない。
* resuse → 100回再利用できると誤認識の可能性
* copy → 100回コピーできると誤認識の可能性、100回目のコピー
* inherit → 継承

## 4. 美しさ

* 読み手が慣れているパターンと一貫性のあるレイアウトを用いる
* 似ているコードは似ているように見せる
* 関連するコードをまとめてブロックにする

最近は、フォーマッターなどあるので不要。

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

> コメントの目的は、書き手の糸を読み手に知らせることである

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

* コードから**すぐに**わかることをコメントしない。

* コメントのためのコメントをしない

* 酷い名前はコメントをつけずに名前を変える : コメントに頼らない。関数名などを修正する

通常は、補助的なコメント(コードの読みにくさを補うコメント)は不要である。
**優れたコード > 酷いコード + 優れたコメント**

### 自分の考えを記録する

* 監督のコメンタリーを入れる : e.g.`// このデータだとハッシュテーブルよりバイナリツリーの方が40%速かった`など。
* コードの欠陥にコメントをつける : `// TODO: もっと高速なアルゴリズムを使う`など
* 定数にコメントをつける : e.g. `const int MAX_RSS_SUBSCRIPTIONS = 1000; // 合理的な限界値。人間はこんなに読めない`

|アノテーション|意味|
|:--:|:--:|
|TODO|あとで追加、修正するべき機能がある。|
|FIXME|既知の不具合があるコード。修正が必要。|
|HACK|あまりきれいじゃないコード。リファクタリングが必要。|
|XXX|危険！動くけどなぜうごくかわからない。|
|REVIEW|意図した通りに動くか、見直す必要がある。|
|OPTIMIZE|無駄が多く、ボトルネックになっている。|
|CHANGED|コードをどのように変更したか。|
|NOTE|なぜ、こうなったという情報を残す。|
|WARNING|注意が必要。|


### 読み手の立場になって考える

* 質問されそうなことを想像する
* ハマりそうな罠を告知する
* 全体像のコメント
* 要約コメント

コメントには、WHAT・HOWではなく、WHYをかくようにすることが多い。ただし、コードを理解するのに役立てば、どれを書いてもいい。

### ライターズブロックを乗り越える

適切な言い回しにする。(e.g. やばい　→ 注意 )

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

> コメントは領域に対する情報の比率が高くなければいけない

* コメントを簡潔にしておく
* 曖昧な代名詞を避ける
* 歯切れの悪い文章を磨く
* 関数の動作を正確に記述する
* 入出力のコーナーケースに実例を使う
* コードの意図を書く : 詳細レベルではなく、高レベルで記述する
* 名前付き引数コメント : よく話からに引数にはインラインコメントを使う
* 情報密度の高い言葉を使う : 正規化、ナイーブソリューション、ヒューリスティックなど

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

> 条件やループなどの制御フローはできるだけ「自然」にする。コードの読み手が立ち止まったり読み返したりしないように書く。


### 条件式の引数の並び順

* 左側 : 調査対象の式。変化する。
* 右側 : 比較対象の式。あまり変化しない。

### if/elseブロックの並び順

* 条件は否定型よりも肯定型を使う。⭕️ if(debug) ❌ if(!debug)
* 単純な条件を先に書く。
* 関心を引く条件や目立つ条件を先に書く。

ただし、これは状況によって変える。

### 三項演算子

基本的にはif/elseを使う。
三項演算子は簡潔になるときだけ使う。

### do/whileループを避ける

do-statementはエラーや混乱の原因になることが多いので、避けた方が良い。条件は前もって書いた方が良い。

### 関数から早く返す

関数で複数のreturnを使い早く返すことは良いこと。

### 悪名高きgoto

基本的にgotoは使わない方がいい。

`goto exit;`だけ例外。

### ネストを浅くする

* 早めに返してネストを削除する(ガード節)
* ループ内部のネストを削除する

### 実行の流れを追う

|構成要素|高レベルの流れが不明瞭になる理由|
|:--:|:--:|
|スレッド|どのコードがいつ実行されるかわからない|
|シグナル・割り込みハンドラ|他のコードが実行される可能性がある|
|例外|いろんな関数呼び出しが終了しようとする|
|関数ポインタと無名関数|コンパイル時に判別ができないので、どのコードが実行されるか不明|
|仮想メソッド|object.virtualMethod()は未知のサブクラスのコードを呼び出す可能性がある|

これらの構成要素を使うと、コードを追うのが難しくなる。
ただし、これらを使うことで、コードが読みやすくなったり、冗長性が低くなくなったりする可能性もあるので、うまく使う。

## 8.巨大な式を分割する

> 巨大な式は飲み込みやすい大きさに分割する。


### 説明変数

説明変数を使って式を分割する。

### 要約変数

要約変数 : 大きなコードの塊を小さな名前に置き換えて、管理や把握を簡単にする変数。

```javascript
if (request.user.id == document.owner_id){
}
if (request.user.id != document.owner_id){
}
```

これを要約変数を使うと以下のようになる。

```javascript
final boolean user_owns_document = (request.user.id == document.owner_id);
if (user_owns_document){
}
if (!user_owns_document){
}
```

### ド・モルガンの法則を使う

`not (a or b or c)` ↔️ `(not a) and (not b) and (not c)`
`not (a and b and c)` ↔️ `(not a) or (not b) or (not c)`

### 短絡評価の悪用

頭がいいコードに気をつける。あとで他の人がコードを読みときに分かりにくくなる。

### 巨大な文を分割する

DRY原則など

### 指揮を簡潔にするもう１つの創造的な方法

マクロを利用すると良いときがある。

## 9.変数と読みやすさ

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

### 変数を削除する

* 役に立たない一時変数
* 中間結果を削除する
* 制御フロー変数を削除する

### 変数のスコープを縮める

> 変数のことが見えるコード行数をできるだけ減らす

* 特にグローバル変数は避ける。
* メソッドをできるだけstaticにする
* 大きなクラスを小さなクラスに分割する
* 定義の位置を下げる

### 変数は一度だけ書き込む

> 変数を操作する場所が増えると、現在値の判断が難しくなる。

`const`や`final`を使い、イミュータブルにする。

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

無関係の下位問題を積極的に見つけて抽出する。

* 関数やコードブロックを見て、このコードの高レベルの目標は何か？と自問する
* コードの各行に対して、高レベルの目標に直接的に効果があるのか？あるいは、無関係の下位問題を解決しているのか？と自問する
* 無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の問題にする

[Amazon.co.jp: リファクタリング(第2版): 既存のコードを安全に改善する (OBJECT TECHNOLOGY SERIES) : Martin Fowler 著, 児玉 公信, 友野 晶夫, 平澤 章, 梅澤 真史: 本](https://www.amazon.co.jp/%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-%E7%AC%AC2%E7%89%88-%E6%97%A2%E5%AD%98%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E5%AE%89%E5%85%A8%E3%81%AB%E6%94%B9%E5%96%84%E3%81%99%E3%82%8B-OBJECT-TECHNOLOGY/dp/4274224546/ref=sr_1_1?dib=eyJ2IjoiMSJ9.fu8tVsLwkcB9T0PL-vLCz3wbMDoZSpNC3Pzlhd7QO1IBocnJx3NsToFSW2XYxFX3XYQRp8UZWpJwMBq_VdlS9_bZ8fgntLLhruw3eebwdQsJ6MwbMFovrM5BPyiCHE_rUAK-GVEafb3m16fV6BB7JdIPEfrzVgyI-jhZwqjjfTgwdHexpW5FBkvQnXIbPxm-D4UsDEls0YRRtXElXuZVTUrqAG85WNb4Je5Jnr1WsoQ.JMGXGu3TwjR3A1LCBHY_hrsh1lnf_whQxqlMEIBaj4U&dib_tag=se&qid=1712896168&refinements=p_27%3A%E3%83%9E%E3%83%BC%E3%83%81%E3%83%B3+%E3%83%95%E3%82%A1%E3%82%A6%E3%83%A9%E3%83%BC&s=books&sr=1-1)

[Amazon.co.jp: ケント・ベックのSmalltalkベストプラクティス・パター: シンプル・デザインへの宝石集 : ケント ベック, Beck,Kent, 真史, 梅沢, 誠, 皆川, 直樹, 小黒, みどり, 森島: 本](https://www.amazon.co.jp/%E3%82%B1%E3%83%B3%E3%83%88%E3%83%BB%E3%83%99%E3%83%83%E3%82%AF%E3%81%AESmalltalk%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9%E3%83%BB%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E2%80%95%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%83%BB%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%B8%E3%81%AE%E5%AE%9D%E7%9F%B3%E9%9B%86-%E3%82%B1%E3%83%B3%E3%83%88-%E3%83%99%E3%83%83%E3%82%AF/dp/4894717549/ref=sr_1_4?dib=eyJ2IjoiMSJ9.Z3J6F1RrNmModSoCjdmH1hehtrUcmfA2YoZTiBdw7uwGD8fh_FrMeTFCWkAUHvfHrCex2ULdMM6aBx4TMZHF_LfIOocZwr1LCvG-EL3z0whzcZEwBu2VvviV3xzCOdh6G6KgYDL42Wa1Ndnj4WCCtMxODhnMwh_CSctUhwrdh6SmZFtsBJbCIEEQcyXVik0Nxwb9HvRBz9GbFggmPkKBEp7H712_1KWQu3_eY9yga1o.jmsFo07Fd-pYYWmV9qRuzf1jzZcEPPW4wRTqT0kcOvg&dib_tag=se&qid=1712896235&refinements=p_27%3A%E3%82%B1%E3%83%B3%E3%83%88+%E3%83%99%E3%83%83%E3%82%AF&s=books&sr=1-4)

## 11. 一度に1つのことを

 > コードは1つずつタスクを行うようにしなければならない

 * タスクは小さくする
 * オブジェクトから値を抽出する
 * 一度に1つのタスクを適用する

## 12. コードに思いを込める

> おばあちゃんがわかるように説明できなければ、本当に理解したとは言えない by アルバート・アインシュタイン

1. コードの動作を簡単な言葉で同僚にもわかるように説明する
2. その説明の中で使っているキーワードやフレーズに注目する
3. その説明に合わせてコードを書く

* ロジックを明確に説明する
* ライブラリを知る
* この手法を大きな問題に適用する
* 解決策を言葉で説明する
* 手法を再起的に適用する

ラバーダッキング : 問題を声に出して説明するだけで、解決策が見つかること

## 13. 短いコードを書く

> 最も読みやすいコードは何も書かれていないコードだ。

* 必要ない機能の実装について悩まない
* 質問と要求の分割
* コードを小さく保つ
    * 汎用的なユーティリティコードを作って重複コードを削除する
    * 未使用のコードや無用の機能を削除する
    * プロジェクトをサブプロジェクトに分割する
    * コードの重量を意識する。軽量で機敏にしておく
* 身近なライブラリに親しむ
* unixツールボックスを使う

## 14. テストと読みやすさ

* テストを読みやすくて保守しやすいものにする
* テストを読みやすくする : 大切ではない詳細はユーザから隠し、大切な詳細は目立つようにする
* 最小のテストを作る
* 独自のミニ言語を実装する
* エラーメッセージを読みやすくする
* もっといいassert()を使う
* エラーメッセージはできるだけ役に立つようにする
* テストの適切な入力値を選択する
* 入力値を単純化する
* 1つの機能に複数のテスト
* テストの機能に名前をつける
* テスト駆動開発(TDD)