【リーダブルコード】制御フローを読みやすくする

[リーダブルコード](https://amzn.asia/d/caRjT2n)の7章「__制御フローを読みやすくする__」を読んだので、内容をまとめています。
条件やループなどの制御フローがないコードは読みやすい。
他の場所に飛んだり枝分かれするのは複雑でコードが分かりにくくなってしまう

---

## 忙しい人向けに、まとめから
:::note info
__鍵となる考え__
条件やループなどの制御フローはできるだけ「**自然**」にする。コードの読み手が立ち止まったり読み返したりしないように書く。
:::
__具体的なポイント__
+ 条件式の引数の並び順
+ if/elseブロックの並び順
+ 三項演算子
+ do/whileループを避ける
+ 関数から早く返す
+ 悪名高きgoto
+ ネストを浅くする
+ 実行が流れを追えるように


## 7章の内容
#### 条件式の引数の並び順
`if(lenght >= 10)`の方が、`if(10 <= length)`よりも読みやすい。
なぜか？
以下のような指針が使える。
|左側|右側|
|:-:|:-:|
|「調査対象」の式|「比較対象」の式|
|変化する|あまり変化しない|

この指針は英語の用法と似ていて、「もし君が20歳以上ならば」というの方が自然な言い回しになる。
「もし20年が君の年齢以下ならば」は不自然。

#### if/elseブロックの並び順
if/else文のブロックは、並び順を自由に変えることができる。
だが、この並び順には優劣がある。
+ 条件は否定系よりも肯定系を使う。例えば、if(!debug)ではなく、if(debug)を使う
+ 単純な条件を先に書く。ifとelseが同じ画面に表示されて見やすい
+ 関心を引く条件や目立つ条件は先に書く


**具体例**　**URLにクエリパラメータexpand_allが含まれているかどうか判断して、responseを構築する**
「ピンクの象のことを考えないように」と言われてに、ピンクの象を考えてしまう
```c++
改善前
if(!url.HasQueryParameter("expand_all"){
    response.Render(items);
}else{
    xxxxxxxx;
}
```
↓
```c++
改善後
if(url.HasQueryParameter("expand_all"){
    xxxxxxxx;
}else{
    response.Render(items);
}
```

#### 三項演算子
簡潔に書けるが、読みやすさの点で議論の余地がある。

:::note info
__鍵となる考え__
行数を短くするよりも、他の人が理解するのにかかる時間を短くする
:::

**基本的にはif/elseを使い、三項演算子はそれによって簡潔になるときにだけ使う。**

**具体例**
```c++
改善前
return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / ( 1 << -exponent );
```
↓
```c++
改善後
if (exponent >= 0 {
    return mantisa * ( 1 << exponent );
}else{
    return mantissa / ( 1 << -exponent);
}
```
#### do/whileループを避ける

#### 関数から早く返す
「ガード節」を使わずに実装するとすごく不自然な実装になるので、関数から早く返すことは望ましい。
参照：[ガード節](https://qiita.com/kouyan/items/7b8b456b626447a1e24e)
**具体例** 

```c++
public boolean Contains(String str, String substr){
    if (str == null || substr == nul) return false;
    if (substr.equals("")) return true;
    省略
}

```

#### ネストを浅くする
ネストの深いコードは理解しにくい。ネストが深くなると、読み手は「精神的スタック」に条件をプッシュしないといけない。
###### ネストが増える仕組み
新しいコードを追加する人にとっては、挿入したコードは新鮮で「関心を引く」コードになる。
一方で後からそのコードを読む人にとっては、こうした文脈や意図は失われてしまう。

:::note info
__鍵となる考え__
変更する時にはコードを新鮮な目で見る。一歩下がって全体を見る。
:::

###### 早めに返してネストを削除する
ネストを削除するには、「失敗ケース」をできるだけ早めに関数から返す。
```c++
改善前
if(user_result==SUCCESS){
    if(permission_result != SUCCESS){
        reply.WriteErrors("error reading permission");
        reply.Done();
        return;
    }
     reply.WriteErrors("");
}else{
    reply.WriteErrors(user_result)
}
reply.Done();
```
↓

```c++
改善後
if(user_result != SUCCESS){
    reply.WriteErrors(user_result)
    reply.Done();
    return;
}

if(permission_result != SUCCESS){
    reply.WriteErrors(permission_result);
    reply.Done();
    return;
}
reply.WriteErrors("");
reply.Done();
```

#### 実行が流れを追えるように
ここまではループや条件などのジャンプを簡単に読める方法など、低レベルの制御フローについて説明されてきた。
でもプログラムの高レベルの「流れ」についても考える必要がある。
main()から出発して、心の中でコードを追っていく、関数を次々に呼び出し、プログラムが終了するまで続けていく。プログラミング言語やライブラリには、コードを「舞台裏」で実行する構成要素も存在する。
|構成要素|高レベルの流れが不明瞭になる理由|
|:-:|:-:|
|スレッド|どのコードがいつ実行されるのかよく分からない|
|シグナル/割り込みハンドラ|他のコードが実行される可能性がある|
|例外|いろんな関数世に出しが終了しようとする|
|関数ポインタと無名関数|コンパイル実行時に判別できないので、どのコードが実行されるのか分からない|
|仮想メソッド|object.vrtualMethod()は未知のサブクラスのコードを呼び出す可能性がある|

これらの構成要素を使うことで、コードが読みやすくなったり、冗長性が低くなる。
一方で使いすぎるとコードの行方を見失うことがあるので、コード全体に占める割合を大きくしないことが大事。

---

引用
[リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)](https://amzn.asia/d/eLinYdT)