「現場で役立つシステム設計の原則」読書録 １章


[現場で役立つシステム設計の原則（増田亨著）](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E5%BD%B9%E7%AB%8B%E3%81%A4%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E8%A8%AD%E8%A8%88%E3%81%AE%E5%8E%9F%E5%89%87-%E3%80%9C%E5%A4%89%E6%9B%B4%E3%82%92%E6%A5%BD%E3%81%A7%E5%AE%89%E5%85%A8%E3%81%AB%E3%81%99%E3%82%8B%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%AE%E5%AE%9F%E8%B7%B5%E6%8A%80%E6%B3%95-%E5%A2%97%E7%94%B0-%E4%BA%A8-ebook/dp/B073GSDBGT)
読んだのでまとめです。
章ごとに分けます。

#１章 小さくまとめてわかりやすくする

##意味を具体的に説明する変数名を使う

```
int a, int b
```
よりは、

```
int qty, int up
int quantity, int unitPrice
```
の方が良い
略語にするかはケースバイケース。一般的でないなら略さない方がわかりやすい
一般的な略語としては、

- idx (index)
- rand (random)
- img (image)

あたり？
##目的ごとの変数を使う
例えば

1. 数量と単価を計算
2. 送料無料になる条件判定をして、結果を合計金額に反映
3. 最後に税込金額を計算する

という処理をするコードは下記のように書ける。

```java
//ステップ1
int price = quantity * unitPrice;

//ステップ2
if(price < 3000) price += 500; //送料

//ステップ3
price = price * taxRate();
```
このコードの中では`price`という変数を使いまわして代入を繰り返している。
これでは`price`の現在の値がわかりづらくなるし、変更の影響範囲も広くなる。
そこで、

- basePrice : 数量 * 単価
- shippingCost : 送料
- itemPrice : 税込金額

という3つの変数を使う。
こうすると先ほどのコードは

```java
//ステップ1
int basePrice = quantity * unitPrice;

//ステップ2
int shippingCost = 0;
if(basePrice < 3000) shippingCost = 500; //送料

//ステップ3
int itemPrice = (basePrice + shippingCost) * taxRate();
```
と書ける。
各ステップの計算目的がはっきりし、各ステップの結びつきが弱くなり変更の影響範囲が狭くなる。
このようにコードの意図を変数名で説明するやり方を`説明用の変数の導入`という。

##メソッドとして独立させる
先ほどのコードで送料無料判定をする部分をメソッドとして切り出してみる。

```java
//ステップ1
int basePrice = quantity * unitPrice;

//ステップ2
int shippingCost = shippingCost(basePrice);

//ステップ3
int itemPrice = (basePrice + shippingCost) * taxRate();

int shippingCost(int basePrice){
    if(basePrice < 3000) return 500;
    return 0;
}
```

こうしておけば送料計算のロジックが変わったりしても変更箇所がわかりやすく、その影響範囲も狭くなる。

##重複したコードをなくす
１つのクラス内であればメソッドにして再利用すれば良いが、異なるクラスだとちょっと一手間
下記の手順で対応できる。

1. それぞれのクラスで重複する部分をメソッドに抽出。
2. ２つのクラス間に参照があれば参照元の方に抽出したメソッドを移動する。参照がなければ共通のメソッド置き場として別のクラスを定義してそちらにメソッドを移動する。
3. 移動先からメソッドを呼び出すように修正。

```java
//送料クラス
class ShippingCost {
    static final int minimumForFree = 3000;
    static final int cost = 500;

    int basePrice;

    ShippingCost(int basePrice){
        this.basePrice = basePrice;
    }

    int amount(){
        if(basePrice < minimumForFree) return cost;
        return 0;
    }
}
```

```java
//呼び出す側
int shippingCost(int basePrice){
    ShippingCost cost = new ShippingCost(basePrice);
    return cost.amount();
}
```

また、上記の送料クラスに送料以外の関心ごとを持ち込まないことも重要。

##業務に使うデータの値の範囲を制限する。

- 商品の数量（int）：0~100
- 電話番号（string）：数字のみ許可し、桁数も確認する

など。
専用クラスを作りその中で範囲内かどうか確認させるとよりわかりやすくなる。

##値オブジェクトを不変にする
値の上書きはコードを複雑にしてしまう。

```java
Money price = new Money(3000);

price.setValue(2000); //変数の上書き
price = new Money(1000); //１つの変数に別のオブジェクトを代入
```

違う値になるときは別のオブジェクトを使うようにする。

```java
Money basePrice = new Money(3000);
Money discounted = basePrice.minus(1000); //メソッドの中で別のMoneyオブジェクトを使って返す
Money option = new Money(1000); //新しいオブジェクトを使う
```

##型を使ってコードをわかりやすく安全にする

```java
int amount(int unitPrice, int quantity){
    return unitPrice * quantity;
}
```

例えば上記のメソッド呼び出しで引数の単価と数量を逆に書いてもエラーは出ない。
こういったコードは潜在的なバグの原因になる。
（上記はたまたま同じ結果になるが、処理を加えた結果変な値になることもある）
そこで

```java
int amount(Money unitPrice, Quantity quantity){
    return unitPrice.multiply(quantity.value());
}
```
とすれば引数の指定間違いを防げる。

##コレクションや配列の操作を同じクラス内に閉じ込める
同じ型のデータを複数持つコレクションや配列の操作をあちこちでやると変更の副作用が大きくなる。
そこでリスト関係の処理をまとめるクラスを作る

```java
class Customers {
    List<Customer> customers;
    
    void add(Customer customer){
        //追加
    }
    void removeIfExist(Customer customer){
        //削除
    }

    int count(){
        //サイズを返す
    }
}
```

この際、インスタンス変数を`customers`のみにすることでクラスの役割が明確になりコードが清潔に保たれる。
このようなやり方を`コレクションオブジェクト`や `ファーストクラスコレクション`と呼ぶ。

また、クラス外で値を変更できないように`customers`を直接返すメソッドは作らないようにする。
計算結果を返す際も直接返さず別のオブジェクトを使って返す

```java
Customers add(Customer customer){
    List<Customer> result = new ArrayList<>(customers);
    result.add(customer);
    return new Customers(result);
}
```
どうしても外から参照したければ変更不可にして返すこともできる。

```java
List<Customer> asList(){
    return Collections.unmodifiableList(customers);
}
```
unmodifiableListで作ったリストは値の追加と削除ができなくなる。
ただしこの場合でも要素自体の変更はできてしまう。

```java
void modifyCustomer(){
    List<Customer> list = customers.asList();
    Customer first = list.get(0);
    first.setName("other name");//NG：要素を直接変更できてしまう
}
```

Customerを不変オブジェクトにすればこれも防げる。

#まとめ
- 短いメソッドや小さなクラスを使って重複を排除する
- 基本型でなく値オブジェクトを使うことでコードをわかりやすくかつ安全にする。
- コレクションや配列は一つのクラスに操作をまとめることで変更による副作用を防ぐ