人に優しいコードを書こう

## 何のためにコードを書くの？

ソースコードは動かすために書くんじゃないよ。
人に読んでもらう為に書くんだよ。

- 今後入ってくるエンジニアへ
- 1年後、そのシステムのメンテナンスをする自分にむけて

---

## 汚いコードとは？

---

### 見た目が汚い

読む速度が落ちる

- ネストしすぎ
- なんかぎゅっとしてる（スペース・改行全然空いてないとか）
- 絵として汚い

---

### 何をしてるのかわからない

理解する速度が落ちる

- 名前以上の事を行う関数 (getXXX()がDBに書き込みとか)
- 読み手の記憶力に頼る
    - 関数が長い
    - 変数多い
    - 変数名の使い回し
- 名前が適当（クラス・メソッド・変数）

---

### コメントが嘘

間違った理解をする

---

## 実例

---

### その１: 見た目が汚い

---

#### ダメなコード

```php
function main() {
 $endValue=30;
 for ($i=1;$i<$endValue+1;$i++){
  if($i%15==0){echo 'FizzBuzz';}
  elseif($i%5==0){echo 'Buzz';}
  elseif($i%3==0){echo 'Fiz';}
 else{echo $i;}
 echo '<br>';
}}
```

---

システムリニューアル案件の既存コードの調査とかでよく見る。
そもそも読む気にならない。

---

#### 良いコード

```php
function main() {
    $endValue = 30;
    for ($i = 1; $i <= $endValue; $i++) {
        echo getAnswer($i) . '<br>';
    }
}

function getAnswer($value) {
    switch (true) {
        case isFizzBuzz($value): return 'FizzBuzz';
        case isFizz($value): return 'Fiz';
        case isBuzz($value): return 'Buzz';
        default: return $value;
    }
}

function isFizzBuzz($value) { return $value % 15 == 0; }
function isFizz($value) { return $value % 3 == 0; }
function isBuzz($value) { return $value % 5 == 0; }
```

---

- インデント、適切な改行・スペースは当たり前。
- 処理を関数化するほど情報量は増えていく。
- 処理の粒度が大きい方から書くと読みやすい。
    - 上から下へ読める
    - 不要な定義を読む必要がない
- if文などの条件には `式` じゃなく `文` が書いてあった方が読みやすい。

---

### その2: 名前が適当

---

#### ダメなコード

```python
def main():
    data = get_data()
    value = get_value(data)
    return value
```

---

なにやってるのかさっぱりわからない。。

---

```python
def main():
    # モデルの一覧を取得します
    data = get_data()
    # タスクタイプ毎の件数をカウントします
    value = get_value(data)
    return value
```

---

コメントを書くぐらいなら、適切な名前をつけよう

---

#### 良いコード

```python
def main():
    models = get_model_list()
    count_per_task_type = get_count_per_task_type(models)
    return count_per_task_type
```

---

### その3: 名前以上の事をしてる

---

#### ダメなコード

```python
def main():
    models = get_model_list()
    count_per_task_type = get_count_per_task_type(models)
    return count_per_task_type

def get_count_per_task_type(models):
    count_per_task_type = ...
    save_count('classification', count_per_task_type['classification'])
    save_count('object_detection', count_per_task_type['object_detection'])
```

---

気軽に呼んでたらガンガンDBに書き込んでる件。

---

#### 良いコード


```python
def main():
    models = get_model_list()
    count_per_task_type = get_count_per_task_type(models)
    save_count('classification', count_per_task_type['classification'])
    save_count('object_detection', count_per_task_type['object_detection'])
    return count_per_task_type

def get_count_per_task_type(models):
    count_per_task_type = ...
    return count_per_task_type
```

---

名前以上のことはしない！

---

### その4: カッコつけない

---

#### ダメなコード

```python
# 内包表記の方が速度的には早いらしいが。。
model_images = {
    model: flatten([
        [
            image
            for image in dataset.images
            if image.filepath.exists()
        ]
        for dataset in model.datasets
    ])
    for model in models
    if model.is_archived is False
}
```

---

競技プログラミングとかでやってくださいませ！

---

#### 良いコード

```python
model_images = {}
for model in models:
    if model.is_archived is True:
        continue
    
    if model not in model_images:
        model_images[model] = []
    
    for dataset in model.datasets:
        for image in dataset.images
            if not image.filepath.exists():
                continue
            model_images[model].append(image)
```

---

ネストは深いけど、こっちのほうが理解はしやすい。

---

## 綺麗に書くテクニック

---

### コントローラ部分に処理の流れをコメントとして書く

---

```python
def main():
    # モデルの一覧を取得します
    pass

    # タスクタイプ毎の件数をカウントします
    pass

    # テンプレートをレンダリングします
    pass

    # レスポンスを返します
    pass
```

---

このコメントがそのまま関数になります。
（簡単な処理は関数化しなくてOKです）

---

### 呼び出し側だけ先に書く

---

```python
def main():
    # モデルの一覧を取得します
    models = get_model_list(order='-creation_date', limit=30);

    # タスクタイプ毎の件数をカウントします
    count_per_task_type = get_count_per_task_type()

    # テンプレートをレンダリングします
    html = render_template(
        template_path='./path/to/template.html',
        models=models,
        count_per_task_type=count_per_task_type,
    )

    # レスポンスを返します
    return Response(200, html)
```

---

クラスや関数を作る際に先に呼び出し側を先に書く。
こうするとInput/Outputが決まるので、作るものが明確になる。
テストを先に書くと `TDD` になるよ！

---

### できるだけ関数を小さく書く

---

```python
def main():
    data = get_model_list()
    value = get_count_per_task_type(data)
    save_count('classification', value['classification'])
    save_count('object_detection', value['object_detection'])
    return value

def get_count_per_task_type(data):
    value = # Get count per task type
    return value

def save_count(name, value):
    obj = ModelCount.objects.get(name=name)
    obj.count = value
    return obj.save()
```

---

関数が小さいと変数名が適当でも意味が通じる。
長い変数名を定義しないと意味が通じない場合は、関数が大きすぎる。
10〜30行ぐらいが目安。

---

### 同じパターンで書く

---

```python
def get_model_list():
    # Check parameters
    ...

    # Get data from db
    ...

    # Response
    ...

def get_model_detail():
    # Check parameters
    ...

    # Get data from db
    ...

    # Response
    ...
```

---

WEBサーバーのエンドポイントとか、Reactコンポーネントとか、
大量に似たようなものを作る場合は、書き方（書く順番）を統一すると読みやすい。

---

## おしまい