良いコード/悪いコードで学ぶ設計入門をまとめてみた

## コードの悪魔

1. **重複コード（Duplicated Code）**
重複コードは同じ処理や機能が複数の場所に現れる問題です。これにより、コードの変更や修正が困難になり、バグのリスクが高まります。
**解決策**
＞必要なロジックをクラスにまとめる
＞重複コードは必ずしも悪ではない。ビジネス概念が違えばそれは違うメソッドと判断すべき

2. **修正漏れ（Missed Updates）**
コードの一部を変更した場合、関連する他の部分も同様に修正する必要がある場合があります。修正漏れが発生すると、プログラムが正しく動作しない可能性があります。
**解決策
＞**重複コード解消に伴い、修正漏れが発生しにくくなる

3. **可読性の低下（Reduced Readability）**
複雑なオブジェクト間の依存関係や長大なメソッド、冗長なコードは可読性を低下させます。これにより、コードの理解や保守が難しくなります。
**解決策
＞**重複コード解消に伴い、可読性が向上する
＞クラス、メソッドを適切に分割し、クラス内、メソッド内のコード量を減らす

4. **生焼けオブジェクト（Anemic Domain Model）**
初期化しないと使用できないクラス、または未初期化状態が発生しうるクラスを、生焼けオブジェクトという。
**解決策**
＞デフォルトコンストラクタを使用せず、必ず引数ありのコンストラクタを書く（完全コンストラクタ）

5. **不正値の混入（Introducing Bugs）**
不正なデータがオブジェクトに混入すると、予測不可能なバグが発生する可能性があります。データの整合性を確保するために適切なエンカプセーションが必要です。
**解決策**
＞メソッドの引数にはプリミティブ型を使用せず、クラス型を使用するようにする（値オブジェクト）
＞メソッドの引数の値が正しいかをバリデーションで管理する

6. **思わぬ副作用（Unintended Side Effects）**
引数の値の状態の変更が思わぬ副作用を引き起こすことがあります。これは可読性の低下やバグの原因となります。
**解決策**
＞引数を定数にする（Javaの場合finalをつける）

## 条件分岐の構造改善

1. 早期returnでネスト解消
    
    ```java
    int metthod(boolean flg){
       if(flg == false) return;
       
       ~通常処理を記載
    　　　　　　return ~
    }
    ```
    
2. 条件チェックの書き方
    
    ```java
    //ダメなパターン
    if(customer.flg != true) retrun;
    ----------------------------------------
    //条件を読みやすくする
    if(customer.isDisabled) return;
    
    customerクラス
    boolean isDisabled(){
      if(this.flg = true){
        return true;
      } else { return false;}
    }
    ```
    

## パターン技法

### ストラテジパターン

ストラテジーパターン（Strategy Pattern）は、ソフトウェア設計パターンの一つで、特定のアルゴリズムや振る舞いをカプセル化し、そのアルゴリズムを動的に切り替えるための方法を提供します。このパターンは、アルゴリズムを変更する必要がある場合に役立ちます。以下に、Javaでストラテジーパターンを実装する方法をコードとともに詳しく解説します。

1. ストラテジー（Strategy）インターフェースを定義します。

```java
public interface SortingStrategy {
    void sort(int[] data);
}
```

1. 具体的なストラテジークラスを実装します。例として、バブルソートとクイックソートを示します。

```java
public class BubbleSort implements SortingStrategy {
    @Override
    public void sort(int[] data) {
        System.out.println("Bubble Sort");
        // バブルソートの実装
    }
}

public class QuickSort implements SortingStrategy {
    @Override
    public void sort(int[] data) {
        System.out.println("Quick Sort");
        // クイックソートの実装
    }
}
```

1. コンテキストクラスを定義します。コンテキストクラスはストラテジーを保持し、必要に応じて切り替えます。

```java
public class Sorter {
    private SortingStrategy strategy;

    public Sorter(SortingStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(SortingStrategy strategy) {
        this.strategy = strategy;
    }

    public void performSort(int[] data) {
        strategy.sort(data);
    }
}
```

1. メインプログラムでストラテジーパターンを使用します。

```java
public class Main {
    public static void main(String[] args) {
        int[] data = {5, 2, 8, 1, 9};

        SortingStrategy bubbleSortStrategy = new BubbleSort();
        SortingStrategy quickSortStrategy = new QuickSort();

        Sorter sorter = new Sorter(bubbleSortStrategy);
        sorter.performSort(data);

        sorter.setStrategy(quickSortStrategy);
        sorter.performSort(data);
    }
}
```

このJavaコードでは、ストラテジーパターンを使用してソートアルゴリズムを切り替える方法が示されています。コンテキストクラス **`Sorter`** は、異なるソートアルゴリズムを持つストラテジーと連携し、必要に応じて切り替えることができます。これにより、ソフトウェアの柔軟性と拡張性が向上し、新しいソートアルゴリズムを追加する際にも簡単に統合できます。

### ポリシーパターン

ポリシーパターン（Policy Pattern）は、ソフトウェア設計パターンの一つで、アルゴリズムや振る舞いをカプセル化し、それを利用するオブジェクトによって動的に交換できるようにするパターンです。これにより、特定の振る舞いを変更する必要がある場合、クラスの変更を最小限に抑えることができます。

ポリシーパターンは、ストラテジーパターンと非常に似ていますが、クライアント（利用者）がポリシーを選択する点が異なります。

例として、ファイルの圧縮アルゴリズムを切り替える場合のポリシーパターンを示します。

1. ポリシー（Policy）インターフェースを定義します。

```java
public interface CompressionPolicy {
    void compress(String file);
}
```

1. 具体的なポリシークラスを実装します。例として、ZIP 圧縮とgzip 圧縮を示します。

```java
public class ZipCompression implements CompressionPolicy {
    @Override
    public void compress(String file) {
        System.out.println("Using ZIP compression for " + file);
        // ZIP 圧縮の実装
    }
}

public class GzipCompression implements CompressionPolicy {
    @Override
    public void compress(String file) {
        System.out.println("Using GZIP compression for " + file);
        // gzip 圧縮の実装
    }
}
```

1. クライアントクラスを定義します。このクラスはポリシーを利用します。

```java
public class FileProcessor {
    private CompressionPolicy compressionPolicy;

    public FileProcessor(CompressionPolicy compressionPolicy) {
        this.compressionPolicy = compressionPolicy;
    }

    public void processFile(String file) {
        compressionPolicy.compress(file);
    }
}
```

1. メインプログラムでポリシーパターンを使用します。

```java
javaCopy code
public class Main {
    public static void main(String[] args) {
        String file = "example.txt";

        CompressionPolicy zipPolicy = new ZipCompression();
        CompressionPolicy gzipPolicy = new GzipCompression();

        FileProcessor processor = new FileProcessor(zipPolicy);
        processor.processFile(file);

        processor = new FileProcessor(gzipPolicy);
        processor.processFile(file);
    }
}
```

このJavaコードでは、ポリシーパターンを使用してファイルの圧縮アルゴリズムを切り替える方法が示されています。クライアントクラス **`FileProcessor`** は、異なる圧縮ポリシーを持つポリシークラスと連携し、必要に応じてポリシーを切り替えることができます。このパターンにより、新しい圧縮アルゴリズムを追加する場合、クライアントクラスを変更せずにポリシークラスを追加でき、柔軟性と拡張性が向上します。

## 名前設計

### 重要ポイント

- 可能な限り具体的で、意味範囲が狭い、特化した名前を選ぶ
＞例：商品ではなく、注文品や在庫品など
- 存在ベースではなく、目的ベースで考える
＞例：商品ではなく、注文品や在庫品など
- どんな関心事があるか分析する
＞ビジネスの関心ごとから名前を探る
＞例：ECサイトの場合、注文、出品、発送など
- 声に出して話してみる
＞ビジネスを知っている人と話し、目的に合った名前を探る
- 利用規約を読んでみる
＞利用規約にはサービスやルールに厳密な言い回しが使用されているので、参考にできる
＞例：**購入者**が商品購入手続きを完了した時点をもって、**売買契約**が**締結**されたものとします
- 違う名前に置き換えられないか検討する
- 疎結合高凝集になっているか点検する
＞目的に特化した名前を選ぶと、目的以外のロジックを寄せ付けにくくできる

### 実際の命名例

- 曖昧じゃない命名
元々の〜 [origin~]
補正された〜[corrected~]
- ロジックをなぞらない
isMemberHpMoreThanZeroAnd~
- クラスが肥大化してしまう名前
MemberManagerクラス
＞これではメンバーのマネージメント関連はここに書くようになってしまう
- 可能な限り動詞1語で
add()
- 英文にして違和感がないように
this member is hungry > isHungry(memberクラス)

## 細かい注意点

1. 共通クラスの活用
＞さまざまなロジックが置かれがちになるのでダメ。
＞staticメソッドと同じで**低凝集構造 になってしまう**

2. スマートUI
＞フロント側で複雑な処理（表示以外）を実装している構造をスマートUIといい、複雑なロジックがフロント側にあると変更が容易ではなくなるのでダメ。

3. フォルダ分け方
＞ビジネス概念ごとにフォルダを分ける
    
    ```markdown
    # 在庫
     ## 在庫usecase
     ## 在庫entity
     ## 在庫controller
     ## 在庫gateway
     ## 在庫driver
    
    # 注文
     ## 注文usecase
     ## 注文entity
     ## 注文controller
     ## 注文gateway
     ## 注文driver
    
    # 支払い
    ~
    ```
    
4. YAGNI原則
「you aren’t going to need it」の略。実際に必要な処理のみ実装せよ。

5. コマンド・クエリ分割
コマンド（状態変化）とクエリ（状態を返す）はメソッドで分ける

## 用語

### **高いほど好ましい「凝集度（ぎょうしゅうど）」**

[**凝集度（cohesion）**](https://ja.wikipedia.org/wiki/%E5%87%9D%E9%9B%86%E5%BA%A6)とは、モジュールのまとまり具合に関する指標です。特定の機能に対する責任を持って、正しくまとまって協調しているかを示す指標で、高いほうが良いとされます。文脈的に強度（strength）と呼ばれることもあり、この場合は強いほうが良いとされます。

### **低いほど好ましい「結合度」**

[**結合度（coupling）**](https://ja.wikipedia.org/wiki/%E7%B5%90%E5%90%88%E5%BA%A6)とは、モジュールを変更しやすいように適切に分割できているかどうかを示す指標です。密結合（結合度が高）なシステムでは修正が困難になるため、疎結合（結合度が低）なシステムが良いとされます。