Rubyで学ぶ良いコードとは：読書メモ

技術評論社のWEB＋DBPRESS vol.99の読書メモ

## １章：良いコードとは
- 書き手の意図通りに動く
 - 十分にテストされている。
- 読み手に意図が伝わる
  - わかりやすい命名にする => 変数名、メソッド名、クラス名 ... etc
  - コードを補足するための適切なコメントを書く。
- 変更に強い
  - DRY => Don't Repeat Yourself (変更箇所が少なくすみ、あらゆるインプットに対応できる。)
  - KISS => Keep It Simple Stupid (不要なコードは書かない。)
  - YAGNI => You ain't gonna need it (不要なコードは書かない。)

### 良いコードを学ぶ方法
- オープンソースの良質なコードを何が良いかを考えながら読む。

## ２章：変数、定数、メソッド
### 変数
- スコープは狭く
  - 変数の定義と参照の間隔は狭くする（視覚的にも、使用範囲も狭く）
- 理解しやすい変数名、適切な長さ

### 定数
- マジックナンバーや静的でアプリ全体で使用される情報を定義する
 - マジックナンバー => Twitterの１４０文字のようにサービス特有の意味づけがされた数字
 - 外部サービス連携用のアプリID、環境変数、エラーコード、ステータスコード ... etc
 - 再利用性の高い静的情報

### メソッド（関数）
- 関心を明確にする
 - 適切な場所（クラス、モジュール）に書く
 - 責務を単一に保ち、責務ごとに処理をメソッドに切り分ける。（疎結合なコードでテストしやすく）
- 適切な命名
 - 簡潔で理解しやすい名前
 - 適切な長さ（自明なgetやdoなどを省く)
 - レシーバオブジェクトとの関係性も意識して命名する（品詞や助詞に気を配る）
 - 関心と抽象度の合った命名（そのメソッドが本質的に何をしているのかが伝わる命名）
- 再利用性を高める
 -  DRYを意識しすぎて、変更しにくいコードにならないように注意する。

シソーラス辞書でしっくりくる名前を探す。

## ３章：クラス
クラスはシステムを構成する登場人物で、物理的実体（人や物）だけでなく、概念的実体（いいね！や通知など）もオブジェクトと言える。クラスの責務を明確にして、責務以外の処理やプロパティをクラス自身に持たないように意識する。

### クラス設計手順
例）動画投稿サイト
機能：ユーザーが動画を投稿できる

名詞と動詞からクラスとその責務を考える。
名詞：クラス => 動画を
動詞：メソッド => 投稿する

- クラス（オブジェクト）
  - 変数、定数（このクラスオブジェクトが持つべき値、状態か）
  - メソッド(この処理はこのクラスが担当すべきかどうか)

##### クラス設計手順
- [ ] サービスに必要なクラスオブジェクトを考える。
- [ ] クラスが担うべき責務から処理（メソッド）を考える。
- [ ] クラス間には、どのような関係性があるか

##### クラスの責務におけるチェックポイント
`明確な責務を持ったクラスを設計する。`

- [ ] 責務が多すぎるクラスはないか
- [ ] 責務の似ているクラスはないか
- [ ] 責務の曖昧なクラスはないか

### デザインパターン
客クラスがコーヒーを注文するというメソッドを持つ場合を
下二つのデザインパターンを適用した例で考える。

- Facadeパターン
- Strategyパターン

#### Facadeパターン適用前
客クラスはコーヒーがどのように作られているかを知っている。

```rb
class Customer
  def order
    cup = Cup.new
    coffee = Coffee.new
    cup.receive(coffee)
  end
end
```

#### Facadeパターン適用後
客クラスはコーヒーがどのように作られているかを知らない。
FacadeであるBaristaクラスにコーヒオブジェクトの詳細を任せる。

```rb
class Customer
  def order
    barista = Barista.new
    barista.brew
  end
end

class Barista
  def brew
    cup = Cup.new
    coffee = Coffee.new
    cup.receive(coffee)
  end
end
```

#### Strategyパターン適用前
ドリンクメニューが増えるたびに、バリスタのbrewメソッドのcase文を増やしていくことになる。
brewメソッドが果てしなく大きくなる可能性があるので良くない。

```rb
class Customer
  def order(type)
    barista = Barista.new
    barista.brew(type)
  end
end

class Barista
  def brew(type)
    case type
    when :coffee
      cup = Cup.new
      coffee = Coffee.new
      cup.receive(coffee)
    when :cafe_au_lait
      cup = Cup.new
      cafe_au_lait = CafeAuLait.new
      cup.receive(cafe_au_lait)
    when :cappuccino
      cup = Cup.new
      cappuccino = Cappuccino.new
      cup.receive(cappuccino)
    end
  end
end
```

#### Strategyパターン適用後
Baristaクラスに影響を与えることなく、ドリンクメニューの数、内容を変更できる。
それぞれのクラスの責務をシンプルに保ち、拡張性も高い。

```rb
class Customer
  def order(drink)
    barista = Barista.new
    barista.brew(drink)
  end
end

class Barista
  def brew(drink)
    drink.brew
  end
end

class Coffee
  def brew
    cup = Cup.new
    coffee = Coffee.new
    cup.receive(coffee)
  end
end

class CafeAuLait
  def brew
    cup = Cup.new
    cafe_au_lait = CafeAuLait.new
    cup.receive(cafe_au_lait)
  end 
end

class Cappuccino
  def brew
    cup = Cup.new
    cappuccino = Cappuccino.new
    cup.receive(cappuccino)
  end
end
```

## ４章：モジュール
Rubyでは、クラスの多重継承をサポートしていないため、`単一継承（is_a） + モジュール`で多重継承のような設計をカバーする。
モジュールはクラスのように`継承`と`インスタンス化`が使えない。
クラス階層を超えた共通の処理をモジュール化することで、複数のクラスにモジュールを組み込み、処理を使い回せる。

### OCP：オープンクローズド原則
> クラスは拡張に対して開いており、修正に対して閉じていなければならない。

ビジネス要件に変更があった場合に、既存コードを修正するのではなく、拡張するためのコードを追加することで対応できるように設計する。ふむふむ。
不安定なもの（具象）より、安定しているもの（抽象）への依存の方が良いとされている。ふむふむ。

モジュールの説明はこちらがわかりやすかったでやんす。
[RubyのModuleの使い方とはいったい](https://qiita.com/shiopon01/items/fd6803f792398c5219cd)

## ５章：チーム開発でのテクニック
- 再利用性の高いコード（３回以上同じ処理を書いていたらメソッドに切り分けたり）
- 変化に柔軟に対応できるコード
- リーダブルコード = 理解しやすいコード（適切な命名、抽象化） + 見やすいコード（インデント、構文ブロック、改行 ... etc）
  - 良いコードは全く新しく外部から入った人でもわかり、属人性が低い
- コードレビュー（思いやり、素直さ）

## まとめ
良いコードを書くことも必要ですが、極力コードを書かないことも良いエンジニアの条件ですよね。