【DDD】ドメイン駆動設計とは何か

ドメイン駆動設計についての読書記録です。
主に下記書籍を参考にしています。
[ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 \| 成瀬 允宣 |本 | 通販 | Amazon](https://amzn.to/3eDGIM4)
[ドメイン駆動設計 モデリング/実装ガイド - little-hands - BOOTH](https://booth.pm/ja/items/1835632)

## 用語の整理
まずはDDDに出てくる用語の整理をしていきます。

### ドメイン
プログラムを適応する対象となる領域のことを指します。

#### 利用者に焦点を当てる
利用者が**何に課題を感じていて、何を解決したいのかを考える必要があります。**
この2つを理解してソフトウェアに反映していきます。
これが大原則です。

### モデル
現実の事業もしくは概念を抽象化したものです。
モデリングは、このモデルを得るまでの過程を指しています。

### ドメインオブジェクト
上であげたモデルをソフトウェア上で動作するようにしたものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148392/347b9c4e-dc66-240e-b6bf-57ad62c03b4b.png)

### 値オブジェクト(ValueObject)
#### 性質
- **不変**
- 交換可能
- 等価性による比較

### エンティティ
データベースのエンティティとは**異なる概念**です。

#### 性質
- **可変**
- 同じ属性でも区別
- 同一性により区別

#### 値オブジェクトとの違い
どこまでを値オブジェクトにして、どこまでをエンティティにするかは非常に難しいです。
その一つの解決策として、 **ライフサイクル**があります。
対象が仮に「ユーザー」だった場合、アプリケーションで会員登録したり、ログインしたり、退会したりとアプリケーションの中で**ライフサイクルが存在する場合は、エンティティになります。**
なので、可変か不変かで判断できそうです。
ただしこの判断は**何を題材するかによって大きく変わるので**サービスによってしっかり考えるようにします。

### ドメインサービス
オブジェクトに持たせる振る舞いとして正しくない場合にドメインサービスを使用します。
メソッドを実装した場合、オブジェクトのメソッドを日本語にした場合に日本がおかしい場合は、ドメインサービスに持たせれば良い。
ただ気をつけなければいけないのは、なんでもかんでもドメインサービスにいれてはいけないということです。

### リポジトリ
ドメインオブジェクトの永続化や再構築を行います。
集約ごとに一つのリポジトリが存在し、

#### リポジトリを使用する理由
ソフトウェアに柔軟性を持たせるのが一番だと思います。
さらに具体的にいうと、テストが容易に実行できるようになります。

### アーキテクチャ
ビジネスロジックが正しい場所にかき続けられることを助けるのがアーキテクチャです。
アーキテクチャはあくまで方針であることを忘れてはいけません。

### 集約
必ず守りたい強い整合性を持ったオブジェクトのまとまりのことをさします。

#### 境界
集約する場合、必ず付いて回ります。

### 依存関係のコントロール
具象が抽象に依存するようにしなければいけません。
そうすることで変更に強いソフトウェアを作りことはsが可能になります。

#### 依存関係逆転の法則(Dependency Inversion Principle)
抽象に依存させることが推奨されています。
より具体的に言うと、ドメイン層で定義したインターフェースに依存することをさします。
[依存関係逆転の原則の重要性について - Eureka Engineering - Medium](https://medium.com/eureka-engineering/go-dependency-inversion-principle-8ffaf7854a55)
[1分でわかる依存関係逆転の原則(DIP) - Qiita](https://qiita.com/wanko5296/items/29e74cc7dd7562624d08)

### 責務
このクラスが何をするクラスなのかを示します。

## 設計
DDDから実際の設計に落とすのは下記が非常に参考になりました。
[「実践ドメイン駆動設計」を読んだので、実際にDDDで設計して作ってみた！ - Qiita](https://qiita.com/APPLE4869/items/d210ddc2cb1bfeea9338)

>コンテキストモデル
要求モデル(要望の洗い出し)　→　プロダクトマネージャーからビジネスで実現したいことヒアリング、洗い出し
ドメインモデル
ユースケースモデリング(ユースケース図)
画面設計(画面遷移図)
画面設計(ワイヤーフレーム)
ユースケースモデリング(ユースケース記述)
ロバストネス分析
クラス図
データモデリング(ER図)
UI設計
実装に入る...
[「実践ドメイン駆動設計」を読んだので、実際にDDDで設計して作ってみた！ - Qiita](https://qiita.com/APPLE4869/items/d210ddc2cb1bfeea9338) より引用

徐々にやっていこう。。。。

### ユースケース
ユーザーストーリーを作成し、それに基づいたユースケースを洗い出します。
ここの洗い出しに関しては、下記書籍を参考に掘り下げていきたいと思っています。
[ユースケース駆動開発実践ガイド (OOP Foundations)](https://www.amazon.co.jp/gp/product/4798114456/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)
[良いユースケースを書くための発想法](http://www.aerith.net/design/use-case-j.html)
[ユースケースをモデリングする - Qiita](https://qiita.com/putan/items/580cbc6f136859f82edb)
[若手エンジニア必読！超絶分かるユースケース図－全知識と書き方５ステップ](https://it-koala.com/usecasediagrams-1832)



## Goでの実装
### アーキテクチャ
アーキテクチャは、レイヤードアーキテクチャを想定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148392/ff037cd7-038c-6864-12cc-93796f08f1c8.png)

[Goで，レイヤードアーキテクチャ - Qiita](https://qiita.com/tozastation/items/a69a102fdc3f62d566b4)
[ドメイン駆動設計で実装を始めるのに一番とっつきやすいアーキテクチャは何か[DDD] - little hands' lab](https://little-hands.hatenablog.com/entry/2017/10/04/231743)
[【GO/DDD】レイヤードアーキテクチャの整理 - Qiita](https://qiita.com/sanoyo/items/6b43ed4a1b68c0373a60)

全体図のフォルダ構成は下記の通りです。

```
├── app
│   ├── application
│   │   └── usecase
│   │       ├── survey.go
│   ├── domain
│   │   ├── model
│   │   │   ├── survey.go
│   │   ├── repository
│   │   │   ├── survey.go
│   │   └── service
│   │       ├── survey.go
│   ├── infrastructure
│   │   ├── database.go
│   │   └── persistence
│   │       ├── survey.go
│   └── presentation
│       ├── handler
│       │   ├── survey.go
│       ├── middleware
│       │   └── middleware.go
│       └── router.go
├── db
```

### ファイルの分割
**集約の境界については、ファイルが境界になっています。**
また、値オブジェクトやエンティティは domain層で表現されることになります。

### application
ドメインロジックを呼び出し、その結果をただ返すことに特化します。
基本薄い層になります。

### domain
`model`, `repository`, `service`で構成されます。 

#### model
使用するデータ構造とドメインロジックを書きます。

```golang
// データ構造の部分
package model

type Survey struct {
	SurveyID         uint           `json:"survey_id" db:"survey_id"`
	Question         string         `json:"question" db:"question"`
	SurveyAnswerType string         `json:"survey_answer_type" db:"survey_answer_type"`
}

// ドメインロジック
....
```

#### repository
ここが依存させるべき抽象の箇所です。
依存関係逆転の法則では、抽象に依存させることが推奨されていました。
理由は、上位モジュールが下位モジュールに依存しません。
つまりこれは、**インターフェースを満たすモジュールであればどんなものでも使用できることを指しましす。
上位モジュールが使いたい下位モジュールを選択することができるのです。**


```golang
package repository

import "github.com/app/domain/model"

type SurveyAccessor interface {
	ListSurveyByCampaignID(campaignID uint) (*[]model.Survey, error)
}
```

#### service
ドメインサービスに書くべき実装を書きます。

```golang
package service

import (
	"github.com/app/domain/model"
	"github.com/app/domain/repository"
)

// repository経由でアクセスするためのAccessor作成
type SurveyService struct {
	serviceAccesor repository.SurveyAccessor
}

func NewSurveyService(sa repository.SurveyAccessor) *SurveyService {
	return &SurveyService{
		serviceAccesor: sa,
	}
}

func (ss *SurveyService) ListSurveyByCampaignID(campaignID uint) (*[]model.Survey, error) {
	surveys, err := ss.serviceAccesor.ListSurveyByCampaignID(campaignID)
	if err != nil {
		return nil, err
	}
	return surveys, nil
}

```

### infrastracture
データベース(データストア)関連の処理(SQL)などを書きます。


### presentation
http などの入出力のプロトコルを定義します。


## その他気になったところ
#### Go言語での実装
[Goのpackage構成と開発のベタープラクティス - Tech Blog - Recruit Lifestyle Engineer](https://engineer.recruit-lifestyle.co.jp/techblog/2018-03-16-go-ddd/)
[Go言語でClean Architectureを実現して、gomockでテストしてみた - Qiita](https://qiita.com/ogady/items/34aae1b2af3080e0fec4)
[Goにおけるドメインオブジェクト設計の考察 - 日記マン](https://i101330.hatenablog.com/entry/2019/02/23/134642)
[【Go+DDD】エンティティと値オブジェクトの実装方法（自己流） - yyh-gl's Tech Blog](https://yyh-gl.github.io/tech-blog/blog/go-ddd-entity-vo/)


#### ドメインモデルからデータベースの設計をする順番
[DDDのモデリングとは何なのか、 そしてどうコードに落とすのか](https://www.slideshare.net/koichiromatsuoka/domain-modeling-andcoding)

##### プロダクトでの活用
>競合他社との差別化要因にリソースを割きたい自社プロダクトでは、
グロースさせていきたいビジネスの概念を型(クラス)に落とし込むこと がドメインモデリングになる、と考えています。
[Goにおけるドメインオブジェクト設計の考察 - 日記マン](https://i101330.hatenablog.com/entry/2019/02/23/134642) より引用

#### フロントエンドとの融合
このDDDとフロントエンドの関係については、次回調べていきたいと思います。
[ドメイン駆動Vuexで複雑さに立ち向かう - スタディスト開発ブログ - Medium](https://medium.com/studist-dev/ddd-vuex-c47055f6c1ba)
[Full-Stack JavaScript meets DDD. - Qiita](https://qiita.com/uskiita/items/214e1f757f68eee107a8)