【備忘録】アーキテクチャ初学者によるクリーンアーキテクチャプロジェクト読解

# 目的
クリーンアーキテクチャのプロジェクトを読解し、その過程で学んだことを備忘録として記録する。これにより、アプリケーションサーバーのアーキテクチャに対する理解を深め、今後の学習や開発の基盤を築くことを目的としている。  
（初学者による備忘録のため、誤りがある場合はご容赦ください。）

以下は読解したプロジェクト

https://github.com/GSabadini/go-clean-architecture

# おすすめの使用方法
Chromeブラウザで2つのウィンドウを開き、この記事にアクセス。  
- **左側のウィンドウ**: コードを参照するために使用。  
- **右側のウィンドウ**: 解説を読みながら理解を深めるために使用。  

このように並べて表示することで、コードと解説を同時に確認でき、理解がスムーズに進むかも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/cb24d107-d729-44bb-b4b6-9678c09a3789.png)


# クリーンアーキテクチャとは
ソフトウェアを設計するための方法の一つで、重要な「ビジネスロジック」と、データベースやフレームワークなどの「具体的な技術」を分けて作ることを目指す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/094eee50-7434-46bb-b1e3-993fbbc6a3c4.png)

# この設計の何が嬉しいの？
1. **開発の早期開始が可能**：各層が独立しているため、フレームワークやデータベースが未決定でも開発を始められる。
2. **並行開発が容易**：各層が独立しているため、他の部分の完成を待たずに作業を進められる。
3. **将来の変更が容易**：各層が独立しているため、フレームワークやデータベースの変更がスムーズにできる。

# 図とコードを対応させる
Accountが生成されるまでの全体図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/0e114b5e-618b-400c-9aba-70d2a7fb1aa3.png)

## domain/account.go

```go
package domain

import (
	"context"
	"errors"
	"time"
)

var (
	ErrAccountNotFound = errors.New("account not found")

	ErrAccountOriginNotFound = errors.New("account origin not found")

	ErrAccountDestinationNotFound = errors.New("account destination not found")

	ErrInsufficientBalance = errors.New("origin account does not have sufficient balance")
)

type AccountID string

func (a AccountID) String() string {
	return string(a)
}

type (
	AccountRepository interface {
		Create(context.Context, Account) (Account, error)
		UpdateBalance(context.Context, AccountID, Money) error
		FindAll(context.Context) ([]Account, error)
		FindByID(context.Context, AccountID) (Account, error)
		FindBalance(context.Context, AccountID) (Account, error)
	}

	Account struct {
		id        AccountID
		name      string
		cpf       string
		balance   Money
		createdAt time.Time
	}
)

func NewAccount(ID AccountID, name, CPF string, balance Money, createdAt time.Time) Account {
	return Account{
		id:        ID,
		name:      name,
		cpf:       CPF,
		balance:   balance,
		createdAt: createdAt,
	}
}

func (a *Account) Deposit(amount Money) {
	a.balance += amount
}

func (a *Account) Withdraw(amount Money) error {
	if a.balance < amount {
		return ErrInsufficientBalance
	}

	a.balance -= amount

	return nil
}

func (a Account) ID() AccountID {
	return a.id
}

func (a Account) Name() string {
	return a.name
}

func (a Account) CPF() string {
	return a.cpf
}

func (a Account) Balance() Money {
	return a.balance
}

func (a Account) CreatedAt() time.Time {
	return a.createdAt
}

func NewAccountBalance(balance Money) Account {
	return Account{balance: balance}
}
```

対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/0df15c73-9547-47a3-836b-5a5154eb6533.png)

### AccountRepository< i >

```go
AccountRepository interface {
		Create(context.Context, Account) (Account, error)
		UpdateBalance(context.Context, AccountID, Money) error
		FindAll(context.Context) ([]Account, error)
		FindByID(context.Context, AccountID) (Account, error)
		FindBalance(context.Context, AccountID) (Account, error)
	}
```

対応部分は青枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/5d79a2f9-dfb3-43dd-b8df-df2e3306cbc0.png)

#### なぜ `AccountRepository< i >` を定義するのか？
２つ外側のアダプタ層で `AccountRepository` オブジェクトを定義するため、ドメイン層ではその受け皿としてインターフェースを定義する。

#### `AccountRepository< i >`を定義するときのキモチ
- **「リポジトリはインタフェースにしないと。実装に依存したらテストできなくなるし、データベース変えるときに死ぬ。」**
-  **「Createは必須だな。アカウント作る機能がないと始まらない。」**
-  **「UpdateBalanceもいるわ。出金や入金で使うから。」**
-  **「FindAllは管理画面で使うかも。」**
-  **「FindByIDは絶対必要だ。IDで検索しないと何もできない。」**
-  **「FindBalanceもいるか？残高だけ取得するケースもあるし。」**
-  **「エラーはちゃんと返さないと。アカウントが見つからないとか、残高不足とか。」**
-  **「コンテキストも渡さないと。キャンセルやタイムアウト制御できないし。」**
-  **「これでドメイン層がデータ層に依存しなくなるな。」**
-   **「テストも楽だし、将来の変更にも強くなる。」**
-    **「まあ、足りないところはリファクタリングで直せばいいか。」**

## usecase/create_account.go
```go
package usecase

import (
	"context"
	"time"

	"github.com/gsabadini/go-clean-architecture/domain"
)

type (
	// CreateAccountUseCase input port
	CreateAccountUseCase interface {
		Execute(context.Context, CreateAccountInput) (CreateAccountOutput, error)
	}

	// CreateAccountInput input data
	CreateAccountInput struct {
		Name    string `json:"name" validate:"required"`
		CPF     string `json:"cpf" validate:"required"`
		Balance int64  `json:"balance" validate:"gt=0,required"`
	}

	// CreateAccountPresenter output port
	CreateAccountPresenter interface {
		Output(domain.Account) CreateAccountOutput
	}

	// CreateAccountOutput output data
	CreateAccountOutput struct {
		ID        string  `json:"id"`
		Name      string  `json:"name"`
		CPF       string  `json:"cpf"`
		Balance   float64 `json:"balance"`
		CreatedAt string  `json:"created_at"`
	}

	createAccountInteractor struct {
		repo       domain.AccountRepository
		presenter  CreateAccountPresenter
		ctxTimeout time.Duration
	}
)

// NewCreateAccountInteractor creates new createAccountInteractor with its dependencies
func NewCreateAccountInteractor(
	repo domain.AccountRepository,
	presenter CreateAccountPresenter,
	t time.Duration,
) CreateAccountUseCase {
	return createAccountInteractor{
		repo:       repo,
		presenter:  presenter,
		ctxTimeout: t,
	}
}

// Execute orchestrates the use case
func (a createAccountInteractor) Execute(ctx context.Context, input CreateAccountInput) (CreateAccountOutput, error) {
	ctx, cancel := context.WithTimeout(ctx, a.ctxTimeout)
	defer cancel()

	var account = domain.NewAccount(
		domain.AccountID(domain.NewUUID()),
		input.Name,
		input.CPF,
		domain.Money(input.Balance),
		time.Now(),
	)

	account, err := a.repo.Create(ctx, account)
	if err != nil {
		return a.presenter.Output(domain.Account{}), err
	}

	return a.presenter.Output(account), nil
}
```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/e49a3f02-10c4-4441-8595-546f98e9b072.png)

### CreateAccountInteractor
```go
createAccountInteractor struct {
		repo       domain.AccountRepository
		presenter  CreateAccountPresenter
		ctxTimeout time.Duration
	}
```
対応部分は青枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/ceaf683f-4f3e-493e-a33d-f6c687054699.png)

#### なぜ `createAccountInteractor` 構造体を定義するのか？
ユースケース（ビジネスロジック）をまとめるためである。
アカウント作成には、  
- データ保存（`repo`）  
- 出力の整形（`presenter`）  
- 処理時間の制限（`ctxTimeout`）  
といった役割がある。  

関数だけで書くと引数管理が煩雑だが、`createAccountInteractor` にまとめることで、シンプルに扱うことができる。 

#### `createAccountInteractor` を定義するときのキモチ
- **「ユースケースを実装するための構造体が必要だな。`createAccountInteractor` にしよう。」**
- **「リポジトリは絶対に必要だ。アカウントを作成するんだから。」**
- **「リポジトリはインタフェースで受け取ろう。実装に依存したらテストできなくなるし。」**
- **「プレゼンターも必要だな。出力を整形する責任を持たせよう。」**
- **「コンテキストのタイムアウトも設定できるようにしよう。長時間の処理を防ぐためだ。」**
- **「コンストラクタ作っとくか。リポジトリ、プレゼンター、タイムアウトを渡さないと動かないようにしないと。」**
- **「メソッドは `Execute` にしよう。コンテキストと入力データを渡せばいいか。」**
- **「エラーハンドリングはしっかりやらないと。リポジトリのエラーはそのまま返すか。」**
- **「バリデーションはここでやるべきか？いや、ドメイン層でやった方がいいかも。」**
- **「この構造体なら、テストでリポジトリのモック使えるな。楽だ。」**
- **「将来的にログやメトリクスを追加するときも、ここに書けばいいか。」**
- **「これでアカウント作成の責任はこの構造体に閉じたな。クリーンだ。」**
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

#### 追加のキモチ
- **「プレゼンターをインタフェースにすることで、出力形式を柔軟に変えられるようにしよう。」**
- **「タイムアウトを設定することで、リソースの無駄遣いを防ごう。」**
- **「ドメイン層の `Account` を使うことで、ビジネスロジックを明確に分離しよう。」**
- **「入力データと出力データを別の構造体に分けることで、責務を明確にしよう。」**
- **「エラーハンドリングはシンプルに、でもしっかりと。エラーが発生したら即座に返そう。」**
- **「将来的に機能を追加するときも、この構造体を拡張すればいいか。」**
- **「これで、アカウント作成のユースケースが独立して動くようになったな。」**
- **「テストが書きやすくなったし、保守性も上がった。これで安心だ。」**


### func NewCreateAccountInteractorについて
```go
func NewCreateAccountInteractor(
	repo domain.AccountRepository,
	presenter CreateAccountPresenter,
	t time.Duration,
) CreateAccountUseCase {
	return createAccountInteractor{
		repo:       repo,
		presenter:  presenter,
		ctxTimeout: t,
	}
}
```

#### なぜ戻り値が`CreateAccountUseCase`型指定なのに`createAccountInteractor`型を返しても良いのか？


https://qiita.com/koichi2426/items/de81552e4be33151e690

#### なぜ `func NewCreateAccountInteractor` を定義するのか？
別の層にて、repo,presenter,tを使用してcreateAccountInteractorオブジェクトを生成するために必要な関数であるため。

テストコード(usecase/create_account_test.go)では以下のように使用される。
```go
var uc = NewCreateAccountInteractor(tt.repository, tt.presenter, time.Second)
```

インフラ層(infrastructure/router/gin.go)ではこのように使われる
```go
uc = usecase.NewCreateAccountInteractor(
				repository.NewAccountNoSQL(g.db),
				presenter.NewCreateAccountPresenter(),
				g.ctxTimeout,
			)
```

### CreateAccountUseCase< i >
```go
CreateAccountUseCase interface {
		Execute(context.Context, CreateAccountInput) (CreateAccountOutput, error)
}
```

対応部分は青枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/deea6716-681a-4000-af43-f93f447d937e.png)
#### `CreateAccountUseCase< i >` とは？
２つ外側のインフラ層で、ユースケース層のNewCreateAccountInteractor関数を使ってCreateAccountUseCaseインスタンスを生成している。そのインスタンスの受け皿としてインターフェースを定義する。

#### `CreateAccountUseCase< i >` を定義するときのキモチ
- **「ユースケースのインタフェースを定義しよう。`CreateAccountUseCase` にしよう。」**  
- **「このインタフェースは、アカウント作成のユースケースを表すから、メソッド名は `Execute` にしよう。」**  
- **「`Execute` の引数は、コンテキストと入力データ (`CreateAccountInput`) にしよう。これで必要な情報を渡せる。」**  
- **「戻り値は、出力データ (`CreateAccountOutput`) とエラーにしよう。エラーは必ず返すようにする。」**  
- **「インタフェースにすることで、実装を隠蔽できる。依存性逆転の原則を守れるな。」**  
- **「これで、他の層（例えばコントローラー）がこのインタフェースに依存するようになる。実装の詳細を知らなくていいから、疎結合になる。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に別の実装を追加するときも、このインタフェースを満たせばいい。拡張性が高まるな。」**  
- **「このインタフェースがあることで、アカウント作成のユースケースが何をするのか、明確になる。」**  
- **「入力と出力の構造体も一緒に定義しておこう。これで、ユースケースの入出力が明確になる。」**  
- **「これで、アカウント作成のユースケースが独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

#### 追加のキモチ  
- **「インタフェースを小さく保とう。単一責任の原則を守るためだ。」**  
- **「`CreateAccountInput` と `CreateAccountOutput` を別の構造体にすることで、入出力の責任を分離しよう。」**  
- **「このインタフェースがあることで、ドメイン層とプレゼンテーション層の橋渡しができるな。」**  
- **「将来的に他のユースケースも同じようにインタフェースで定義しよう。一貫性が出る。」**  
- **「これで、アカウント作成のユースケースがフレームワークやDBに依存しなくなった。テストもしやすい。」**  
- **「インタフェースを定義することで、チームメンバーとのコミュニケーションも楽になる。何が必要なのかが明確だから。」**  
- **「これで、アカウント作成のユースケースがしっかりとカプセル化されたな。変更に強くなった。」**

### CreateAccountPresenter< i >
```go
CreateAccountPresenter interface {
		Output(domain.Account) CreateAccountOutput
	}
```

対応部分は青枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/9a359355-cef1-4bf4-bb10-64ba90fccda4.png)

#### なぜ `CreateAccountPresenter< i >` を定義するのか？
１つ外側のアダプタ層で `CreateAccountPresenter` オブジェクトを定義するため、ユースケース層ではその受け皿としてインターフェースを定義する。

#### `CreateAccountPresenter< i >` を定義するときのキモチ
- **「出力を整形する責任を持つプレゼンターが必要だな。`CreateAccountPresenter` にしよう。」**  
- **「このインタフェースは、ドメイン層のデータをプレゼンテーション層に適した形に変換する役割だ。」**  
- **「メソッド名は `Output` にしよう。ドメインの `Account` を受け取って、`CreateAccountOutput` を返す。」**  
- **「インタフェースにすることで、出力形式を柔軟に変えられるようにしよう。JSON、XML、HTML など、必要に応じて実装を差し替えられる。」**  
- **「これで、プレゼンテーション層がドメイン層に依存しなくなる。疎結合になるな。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に出力形式を変更するときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「このインタフェースがあることで、出力の責任が明確になる。ユースケース層はビジネスロジックに集中できる。」**  
- **「`CreateAccountOutput` を返すことで、出力データの構造も明確になる。これでフロントエンドやAPIクライアントが使いやすくなる。」**  
- **「これで、アカウント作成の出力が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

#### 追加のキモチ  
- **「プレゼンターのインタフェースを小さく保とう。単一責任の原則を守るためだ。」**  
- **「ドメイン層の `Account` をそのまま返さず、`CreateAccountOutput` に変換することで、ドメイン層の詳細を隠蔽できる。」**  
- **「このインタフェースがあることで、ユースケース層とプレゼンテーション層の橋渡しができるな。」**  
- **「将来的に他のプレゼンターも同じようにインタフェースで定義しよう。一貫性が出る。」**  
- **「これで、出力のロジックがユースケース層から分離された。ユースケース層はビジネスロジックに集中できる。」**  
- **「インタフェースを定義することで、チームメンバーとのコミュニケーションも楽になる。何が必要なのかが明確だから。」**  
- **「これで、出力の責任がしっかりとカプセル化されたな。変更に強くなった。」**  
- **「出力形式を変更するときも、このインタフェースを満たす新しい実装を作ればいい。既存のコードに影響を与えない。」**  
- **「これで、アカウント作成のユースケースが完全に独立したな。出力の責任も明確になった。」**

## adapter/api/action/create_account.go
```go
package action

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/gsabadini/go-clean-architecture/adapter/api/logging"
	"github.com/gsabadini/go-clean-architecture/adapter/api/response"
	"github.com/gsabadini/go-clean-architecture/adapter/logger"
	"github.com/gsabadini/go-clean-architecture/adapter/validator"
	"github.com/gsabadini/go-clean-architecture/usecase"
)

type CreateAccountAction struct {
	uc        usecase.CreateAccountUseCase
	log       logger.Logger
	validator validator.Validator
}

func NewCreateAccountAction(uc usecase.CreateAccountUseCase, log logger.Logger, v validator.Validator) CreateAccountAction {
	return CreateAccountAction{
		uc:        uc,
		log:       log,
		validator: v,
	}
}

func (a CreateAccountAction) Execute(w http.ResponseWriter, r *http.Request) {
	const logKey = "create_account"

	var input usecase.CreateAccountInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		logging.NewError(
			a.log,
			err,
			logKey,
			http.StatusBadRequest,
		).Log("error when decoding json")

		response.NewError(err, http.StatusBadRequest).Send(w)
		return
	}
	defer r.Body.Close()

	if errs := a.validateInput(input); len(errs) > 0 {
		logging.NewError(
			a.log,
			response.ErrInvalidInput,
			logKey,
			http.StatusBadRequest,
		).Log("invalid input")

		response.NewErrorMessage(errs, http.StatusBadRequest).Send(w)
		return
	}

	a.cleanCPF(input.CPF)

	output, err := a.uc.Execute(r.Context(), input)
	if err != nil {
		logging.NewError(
			a.log,
			err,
			logKey,
			http.StatusInternalServerError,
		).Log("error when creating a new account")

		response.NewError(err, http.StatusInternalServerError).Send(w)
		return
	}
	logging.NewInfo(a.log, logKey, http.StatusCreated).Log("success creating account")

	response.NewSuccess(output, http.StatusCreated).Send(w)
}

func (a CreateAccountAction) validateInput(input usecase.CreateAccountInput) []string {
	var msgs []string

	err := a.validator.Validate(input)
	if err != nil {
		for _, msg := range a.validator.Messages() {
			msgs = append(msgs, msg)
		}
	}

	return msgs
}

func (a CreateAccountAction) cleanCPF(cpf string) string {
	return strings.Replace(strings.Replace(cpf, ".", "", -1), "-", "", -1)
}

```

対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/7651b3f2-fd20-4da9-9a39-16f89f476088.png)

### CreateAccountActionとは
インフラ層側からユースケースを実行することができるように用意された変換オブジェクト。

### `CreateAccountAction` を定義するときのキモチ
- **「HTTPリクエストを処理するためのアクションが必要だな。`CreateAccountAction` にしよう。」**  
- **「このアクションは、ユースケースを呼び出してアカウントを作成する役割だ。」**  
- **「ユースケース (`CreateAccountUseCase`) は絶対に必要だ。これがないとアカウントを作成できない。」**  
- **「ログも必要だな。エラーや成功を記録するために。」**  
- **「バリデーションも必要だ。入力データが正しいか確認しないと。」**  
- **「コンストラクタを作って、依存関係を注入できるようにしよう。これでテストしやすくなる。」**  
- **「メソッド名は `Execute` にしよう。HTTPリクエストを処理する責任を持たせる。」**  
- **「リクエストボディをデコードして、入力データ (`CreateAccountInput`) に変換しよう。」**  
- **「バリデーションエラーがあれば、即座にエラーレスポンスを返そう。無効なデータは処理しない。」**  
- **「CPFのフォーマットを整える必要があるな。ドットやハイフンを削除しよう。」**  
- **「ユースケースを呼び出して、アカウントを作成しよう。エラーがあればログに記録して、エラーレスポンスを返す。」**  
- **「成功したら、ログに記録して成功レスポンスを返そう。」**  
- **「これで、HTTP層の責任が明確になったな。リクエストを受け取り、ユースケースを呼び出し、レスポンスを返す。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「HTTP層の責任を明確に分離しよう。ビジネスロジックはユースケースに任せる。」**  
- **「ログをしっかり記録することで、デバッグや監視がしやすくなる。」**  
- **「バリデーションをここで行うことで、無効なデータがユースケースに渡るのを防ぐ。」**  
- **「CPFのフォーマットを整えることで、ユースケース層で余計な処理をしなくて済む。」**  
- **「エラーハンドリングはしっかりやろう。ユーザーにわかりやすいエラーメッセージを返す。」**  
- **「成功レスポンスは、フロントエンドやAPIクライアントが使いやすい形にしよう。」**  
- **「これで、アカウント作成のHTTPエンドポイントが完成したな。クリーンだ。」**  
- **「テストのときも、モックを使いやすくなる。依存関係を注入しているから。」**  
- **「将来的に機能を追加するときも、このアクションを拡張すればいいか。」**  
- **「これで、アカウント作成のフローが一通り完成した。責任が分離されて、保守性も高い。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

### NewCreateAccountActionとは
１つ外側のインフラ層側からCreateAccountActionオブジェクトを生成するために必要な関数。

## adapter/validator/validator.go
```go
package validator

type Validator interface {
	Validate(interface{}) error
	Messages() []string
}
```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/fc66acd9-d35e-4eae-99b9-f34d486985ce.png)

### `Validator<i>` を定義するときのキモチ
- **「バリデーションのインタフェースが必要だな。`Validator` にしよう。」**  
- **「このインタフェースは、入力データを検証する責任を持つ。」**  
- **「メソッドは `Validate` と `Messages` にしよう。`Validate` で検証を行い、`Messages` でエラーメッセージを取得する。」**  
- **「`Validate` の引数は `interface{}` にしよう。これでどんな型のデータでも検証できる。」**  
- **「エラーメッセージはスライスで返そう。複数のエラーがある場合に対応するためだ。」**  
- **「インタフェースにすることで、バリデーションの実装を柔軟に差し替えられるようにしよう。」**  
- **「これで、バリデーションのロジックが特定の実装に依存しなくなる。疎結合になるな。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的にバリデーションのルールを変更するときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「このインタフェースがあることで、バリデーションの責任が明確になる。ユースケース層やHTTP層は検証の詳細を知らなくていい。」**  
- **「これで、バリデーションが独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「バリデーションのインタフェースを小さく保とう。単一責任の原則を守るためだ。」**  
- **「`Validate` メソッドでエラーを返すことで、検証結果を簡単に確認できる。」**  
- **「`Messages` メソッドでエラーメッセージを取得することで、ユーザーにわかりやすいフィードバックを提供できる。」**  
- **「このインタフェースがあることで、バリデーションのロジックが再利用しやすくなる。」**  
- **「将来的に他のバリデーションも同じようにインタフェースで定義しよう。一貫性が出る。」**  
- **「これで、バリデーションの責任がしっかりとカプセル化されたな。変更に強くなった。」**  
- **「バリデーションのルールを変更するときも、このインタフェースを満たす新しい実装を作ればいい。既存のコードに影響を与えない。」**  
- **「これで、入力データの検証が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


## adapter/logger/logger.go
```go
package logger

type Logger interface {
	Infof(format string, args ...interface{})
	Warnf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
	Fatalln(args ...interface{})
	WithFields(keyValues Fields) Logger
	WithError(err error) Logger
}

type Fields map[string]interface{}
```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/d034274a-91ab-4af0-b633-16128dd5adba.png)

### `Logger<i>` を定義するときのキモチ
- **「ロギングのインタフェースが必要だな。`Logger` にしよう。」**  
- **「このインタフェースは、アプリケーション全体でログを記録する責任を持つ。」**  
- **「ログレベルごとにメソッドを分けよう。`Infof`、`Warnf`、`Errorf`、`Fatalln` を用意する。」**  
- **「フォーマット付きのログ記録ができるように、`Infof`、`Warnf`、`Errorf` は `format` と可変長引数を受け取るようにしよう。」**  
- **「致命的なエラーの場合は `Fatalln` を使おう。これでアプリケーションを終了させられる。」**  
- **「追加のフィールドをログに含められるように、`WithFields` メソッドを用意しよう。これでコンテキストを追加できる。」**  
- **「エラーをログに含められるように、`WithError` メソッドも用意しよう。これでエラーの詳細を記録できる。」**  
- **「インタフェースにすることで、ロギングの実装を柔軟に差し替えられるようにしよう。」**  
- **「これで、ロギングのロジックが特定の実装に依存しなくなる。疎結合になるな。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的にロギングの方法を変更するときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「このインタフェースがあることで、ロギングの責任が明確になる。アプリケーションの他の部分はログの詳細を知らなくていい。」**  
- **「これで、ロギングが独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「ログレベルを分けることで、重要度に応じたログ記録ができる。」**  
- **「フォーマット付きのログ記録ができるようにすることで、柔軟なログ出力が可能になる。」**  
- **「`WithFields` メソッドでコンテキストを追加できるようにすることで、デバッグや監視がしやすくなる。」**  
- **「`WithError` メソッドでエラーをログに含められるようにすることで、エラーの追跡が容易になる。」**  
- **「インタフェースを小さく保とう。単一責任の原則を守るためだ。」**  
- **「このインタフェースがあることで、ロギングのロジックが再利用しやすくなる。」**  
- **「将来的に他のロギングも同じようにインタフェースで定義しよう。一貫性が出る。」**  
- **「これで、ロギングの責任がしっかりとカプセル化されたな。変更に強くなった。」**  
- **「ロギングの方法を変更するときも、このインタフェースを満たす新しい実装を作ればいい。既存のコードに影響を与えない。」**  
- **「これで、ロギングが独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

## adapter/presenter/create_account.go
```go
package presenter

import (
	"time"

	"github.com/gsabadini/go-clean-architecture/domain"
	"github.com/gsabadini/go-clean-architecture/usecase"
)

type createAccountPresenter struct{}

func NewCreateAccountPresenter() usecase.CreateAccountPresenter {
	return createAccountPresenter{}
}

func (a createAccountPresenter) Output(account domain.Account) usecase.CreateAccountOutput {
	return usecase.CreateAccountOutput{
		ID:        account.ID().String(),
		Name:      account.Name(),
		CPF:       account.CPF(),
		Balance:   account.Balance().Float64(),
		CreatedAt: account.CreatedAt().Format(time.RFC3339),
	}
}
```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/071ecd1e-612e-4003-af5e-607b8920983a.png)

### `createAccountPresenter` を定義するときのキモチ  
- **「出力を整形するプレゼンターが必要だな。`createAccountPresenter` にしよう。」**  
- **「このプレゼンターは、ドメイン層の `Account` をプレゼンテーション層に適した形に変換する役割だ。」**  
- **「コンストラクタを作って、依存関係を注入できるようにしよう。これでテストしやすくなる。」**  
- **「メソッド名は `Output` にしよう。ドメインの `Account` を受け取って、`CreateAccountOutput` を返す。」**  
- **「`Account` の各フィールドを `CreateAccountOutput` にマッピングしよう。ID、Name、CPF、Balance、CreatedAt を変換する。」**  
- **「ID は文字列に変換しよう。UUID をそのまま返すのは避ける。」**  
- **「Balance は `Float64` に変換しよう。金額は小数点以下も扱えるようにする。」**  
- **「CreatedAt は `time.RFC3339` 形式にフォーマットしよう。日付の表示形式を統一する。」**  
- **「これで、出力データの構造が明確になる。フロントエンドやAPIクライアントが使いやすくなる。」**  
- **「プレゼンターの責任は出力の整形だけに限定しよう。ビジネスロジックは含めない。」**  
- **「これで、アカウント作成の出力が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「ドメイン層の `Account` をそのまま返さず、`CreateAccountOutput` に変換することで、ドメイン層の詳細を隠蔽できる。」**  
- **「出力形式を柔軟に変えられるように、プレゼンターをインタフェースで定義しよう。」**  
- **「これで、ユースケース層が出力形式に依存しなくなる。疎結合になるな。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に出力形式を変更するときも、このプレゼンターを拡張すればいい。拡張性が高まる。」**  
- **「出力の責任をプレゼンターに閉じ込めることで、ユースケース層はビジネスロジックに集中できる。」**  
- **「これで、アカウント作成のフローが一通り完成した。責任が分離されて、保守性も高い。」**  
- **「出力形式を変更するときも、このプレゼンターを修正すればいい。既存のコードに影響を与えない。」**  
- **「これで、アカウント作成の出力が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


## infrastructure/router/gin.go
```go
package router

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gsabadini/go-clean-architecture/adapter/api/action"
	"github.com/gsabadini/go-clean-architecture/adapter/logger"
	"github.com/gsabadini/go-clean-architecture/adapter/presenter"
	"github.com/gsabadini/go-clean-architecture/adapter/repository"
	"github.com/gsabadini/go-clean-architecture/adapter/validator"
	"github.com/gsabadini/go-clean-architecture/usecase"
)

type ginEngine struct {
	router     *gin.Engine
	log        logger.Logger
	db         repository.NoSQL
	validator  validator.Validator
	port       Port
	ctxTimeout time.Duration
}

func newGinServer(
	log logger.Logger,
	db repository.NoSQL,
	validator validator.Validator,
	port Port,
	t time.Duration,
) *ginEngine {
	return &ginEngine{
		router:     gin.New(),
		log:        log,
		db:         db,
		validator:  validator,
		port:       port,
		ctxTimeout: t,
	}
}

func (g ginEngine) Listen() {
	gin.SetMode(gin.ReleaseMode)
	gin.Recovery()

	g.setAppHandlers(g.router)

	server := &http.Server{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 15 * time.Second,
		Addr:         fmt.Sprintf(":%d", g.port),
		Handler:      g.router,
	}

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		g.log.WithFields(logger.Fields{"port": g.port}).Infof("Starting HTTP Server")
		if err := server.ListenAndServe(); err != nil {
			g.log.WithError(err).Fatalln("Error starting HTTP server")
		}
	}()

	<-stop

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer func() {
		cancel()
	}()

	if err := server.Shutdown(ctx); err != nil {
		g.log.WithError(err).Fatalln("Server Shutdown Failed")
	}

	g.log.Infof("Service down")
}

/* TODO ADD MIDDLEWARE */
func (g ginEngine) setAppHandlers(router *gin.Engine) {
	router.POST("/v1/transfers", g.buildCreateTransferAction())
	router.GET("/v1/transfers", g.buildFindAllTransferAction())

	router.GET("/v1/accounts/:account_id/balance", g.buildFindBalanceAccountAction())
	router.POST("/v1/accounts", g.buildCreateAccountAction())
	router.GET("/v1/accounts", g.buildFindAllAccountAction())

	router.GET("/v1/health", g.healthcheck())
}

func (g ginEngine) buildCreateTransferAction() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			uc = usecase.NewCreateTransferInteractor(
				repository.NewTransferNoSQL(g.db),
				repository.NewAccountNoSQL(g.db),
				presenter.NewCreateTransferPresenter(),
				g.ctxTimeout,
			)

			act = action.NewCreateTransferAction(uc, g.log, g.validator)
		)

		act.Execute(c.Writer, c.Request)
	}
}

func (g ginEngine) buildFindAllTransferAction() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			uc = usecase.NewFindAllTransferInteractor(
				repository.NewTransferNoSQL(g.db),
				presenter.NewFindAllTransferPresenter(),
				g.ctxTimeout,
			)
			act = action.NewFindAllTransferAction(uc, g.log)
		)

		act.Execute(c.Writer, c.Request)
	}
}

func (g ginEngine) buildCreateAccountAction() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			uc = usecase.NewCreateAccountInteractor(
				repository.NewAccountNoSQL(g.db),
				presenter.NewCreateAccountPresenter(),
				g.ctxTimeout,
			)
			act = action.NewCreateAccountAction(uc, g.log, g.validator)
		)

		act.Execute(c.Writer, c.Request)
	}
}

func (g ginEngine) buildFindAllAccountAction() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			uc = usecase.NewFindAllAccountInteractor(
				repository.NewAccountNoSQL(g.db),
				presenter.NewFindAllAccountPresenter(),
				g.ctxTimeout,
			)
			act = action.NewFindAllAccountAction(uc, g.log)
		)

		act.Execute(c.Writer, c.Request)
	}
}

func (g ginEngine) buildFindBalanceAccountAction() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			uc = usecase.NewFindBalanceAccountInteractor(
				repository.NewAccountNoSQL(g.db),
				presenter.NewFindAccountBalancePresenter(),
				g.ctxTimeout,
			)
			act = action.NewFindAccountBalanceAction(uc, g.log)
		)

		q := c.Request.URL.Query()
		q.Add("account_id", c.Param("account_id"))
		c.Request.URL.RawQuery = q.Encode()

		act.Execute(c.Writer, c.Request)
	}
}

func (g ginEngine) healthcheck() gin.HandlerFunc {
	return func(c *gin.Context) {
		action.HealthCheck(c.Writer, c.Request)
	}
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/47c2aae2-b7d4-432c-b307-7d5c88d849c5.png)


### `infrastructure/router/gin.go` を定義するときのキモチ  
- **「HTTPリクエストを処理するためのルーターが必要だな。`ginEngine` にしよう。」**  
- **「このルーターは、Ginフレームワークを使ってHTTPリクエストを処理する。」**  
- **「ルーターの初期化は `newGinServer` 関数で行おう。ロガー、データベース、バリデーター、ポート、タイムアウトを受け取る。」**  
- **「`Listen` メソッドでサーバーを起動しよう。HTTPサーバーの設定を行い、シグナルを受け取ってシャットダウンもできるようにする。」**  
- **「`setAppHandlers` メソッドでルーティングを設定しよう。各エンドポイントに対応するアクションを紐付ける。」**  
- **「`buildCreateTransferAction`、`buildFindAllTransferAction`、`buildCreateAccountAction`、`buildFindAllAccountAction`、`buildFindBalanceAccountAction` メソッドで各ユースケースをビルドしよう。依存関係を注入してアクションを作成する。」**  
- **「`healthcheck` メソッドでヘルスチェックエンドポイントを設定しよう。サーバーの状態を確認できるようにする。」**  
- **「これで、HTTPリクエストの処理が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「Ginフレームワークを使うことで、HTTPリクエストの処理を簡単に実装できる。」**  
- **「ルーターの初期化関数で依存関係を注入することで、テストしやすくなる。」**  
- **「`Listen` メソッドでサーバーの起動とシャットダウンを制御することで、リソースの管理がしやすくなる。」**  
- **「`setAppHandlers` メソッドでルーティングを設定することで、エンドポイントの追加や変更が容易になる。」**  
- **「各アクションをビルドするメソッドを用意することで、依存関係の注入が簡単になる。」**  
- **「ヘルスチェックエンドポイントを設定することで、サーバーの状態を監視しやすくなる。」**  
- **「これで、HTTPリクエストの処理が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的にエンドポイントを追加するときも、このルーターを拡張すればいい。拡張性が高まる。」**  
- **「これで、HTTPリクエストの処理が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


## infrastructure/router/gorilla_mux.go
```go
package router

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gsabadini/go-clean-architecture/adapter/api/action"
	"github.com/gsabadini/go-clean-architecture/adapter/api/middleware"
	"github.com/gsabadini/go-clean-architecture/adapter/logger"
	"github.com/gsabadini/go-clean-architecture/adapter/presenter"
	"github.com/gsabadini/go-clean-architecture/adapter/repository"
	"github.com/gsabadini/go-clean-architecture/adapter/validator"
	"github.com/gsabadini/go-clean-architecture/usecase"

	"github.com/gorilla/mux"
	"github.com/urfave/negroni"
)

type gorillaMux struct {
	router     *mux.Router
	middleware *negroni.Negroni
	log        logger.Logger
	db         repository.SQL
	validator  validator.Validator
	port       Port
	ctxTimeout time.Duration
}

func newGorillaMux(
	log logger.Logger,
	db repository.SQL,
	validator validator.Validator,
	port Port,
	t time.Duration,
) *gorillaMux {
	return &gorillaMux{
		router:     mux.NewRouter(),
		middleware: negroni.New(),
		log:        log,
		db:         db,
		validator:  validator,
		port:       port,
		ctxTimeout: t,
	}
}

func (g gorillaMux) Listen() {
	g.setAppHandlers(g.router)
	g.middleware.UseHandler(g.router)

	server := &http.Server{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 15 * time.Second,
		Addr:         fmt.Sprintf(":%d", g.port),
		Handler:      g.middleware,
	}

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		g.log.WithFields(logger.Fields{"port": g.port}).Infof("Starting HTTP Server")
		if err := server.ListenAndServe(); err != nil {
			g.log.WithError(err).Fatalln("Error starting HTTP server")
		}
	}()

	<-stop

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer func() {
		cancel()
	}()

	if err := server.Shutdown(ctx); err != nil {
		g.log.WithError(err).Fatalln("Server Shutdown Failed")
	}

	g.log.Infof("Service down")
}

func (g gorillaMux) setAppHandlers(router *mux.Router) {
	api := router.PathPrefix("/v1").Subrouter()

	api.Handle("/transfers", g.buildCreateTransferAction()).Methods(http.MethodPost)
	api.Handle("/transfers", g.buildFindAllTransferAction()).Methods(http.MethodGet)

	api.Handle("/accounts/{account_id}/balance", g.buildFindBalanceAccountAction()).Methods(http.MethodGet)
	api.Handle("/accounts", g.buildCreateAccountAction()).Methods(http.MethodPost)
	api.Handle("/accounts", g.buildFindAllAccountAction()).Methods(http.MethodGet)

	api.HandleFunc("/health", action.HealthCheck).Methods(http.MethodGet)
}

func (g gorillaMux) buildCreateTransferAction() *negroni.Negroni {
	var handler http.HandlerFunc = func(res http.ResponseWriter, req *http.Request) {
		var (
			uc = usecase.NewCreateTransferInteractor(
				repository.NewTransferSQL(g.db),
				repository.NewAccountSQL(g.db),
				presenter.NewCreateTransferPresenter(),
				g.ctxTimeout,
			)
			act = action.NewCreateTransferAction(uc, g.log, g.validator)
		)

		act.Execute(res, req)
	}

	return negroni.New(
		negroni.HandlerFunc(middleware.NewLogger(g.log).Execute),
		negroni.NewRecovery(),
		negroni.Wrap(handler),
	)
}

func (g gorillaMux) buildFindAllTransferAction() *negroni.Negroni {
	var handler http.HandlerFunc = func(res http.ResponseWriter, req *http.Request) {
		var (
			uc = usecase.NewFindAllTransferInteractor(
				repository.NewTransferSQL(g.db),
				presenter.NewFindAllTransferPresenter(),
				g.ctxTimeout,
			)
			act = action.NewFindAllTransferAction(uc, g.log)
		)

		act.Execute(res, req)
	}

	return negroni.New(
		negroni.HandlerFunc(middleware.NewLogger(g.log).Execute),
		negroni.NewRecovery(),
		negroni.Wrap(handler),
	)
}

func (g gorillaMux) buildCreateAccountAction() *negroni.Negroni {
	var handler http.HandlerFunc = func(res http.ResponseWriter, req *http.Request) {
		var (
			uc = usecase.NewCreateAccountInteractor(
				repository.NewAccountSQL(g.db),
				presenter.NewCreateAccountPresenter(),
				g.ctxTimeout,
			)
			act = action.NewCreateAccountAction(uc, g.log, g.validator)
		)

		act.Execute(res, req)
	}

	return negroni.New(
		negroni.HandlerFunc(middleware.NewLogger(g.log).Execute),
		negroni.NewRecovery(),
		negroni.Wrap(handler),
	)
}

func (g gorillaMux) buildFindAllAccountAction() *negroni.Negroni {
	var handler http.HandlerFunc = func(res http.ResponseWriter, req *http.Request) {
		var (
			uc = usecase.NewFindAllAccountInteractor(
				repository.NewAccountSQL(g.db),
				presenter.NewFindAllAccountPresenter(),
				g.ctxTimeout,
			)
			act = action.NewFindAllAccountAction(uc, g.log)
		)

		act.Execute(res, req)
	}

	return negroni.New(
		negroni.HandlerFunc(middleware.NewLogger(g.log).Execute),
		negroni.NewRecovery(),
		negroni.Wrap(handler),
	)
}

func (g gorillaMux) buildFindBalanceAccountAction() *negroni.Negroni {
	var handler http.HandlerFunc = func(res http.ResponseWriter, req *http.Request) {
		var (
			uc = usecase.NewFindBalanceAccountInteractor(
				repository.NewAccountSQL(g.db),
				presenter.NewFindAccountBalancePresenter(),
				g.ctxTimeout,
			)
			act = action.NewFindAccountBalanceAction(uc, g.log)
		)

		var (
			vars = mux.Vars(req)
			q    = req.URL.Query()
		)

		q.Add("account_id", vars["account_id"])
		req.URL.RawQuery = q.Encode()

		act.Execute(res, req)
	}

	return negroni.New(
		negroni.HandlerFunc(middleware.NewLogger(g.log).Execute),
		negroni.NewRecovery(),
		negroni.Wrap(handler),
	)
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/d1a10d42-1b17-4445-9c6a-47aef6317739.png)

### `infrastructure/router/gorilla_mux.go` を定義するときのキモチ 
- **「HTTPリクエストを処理するためのルーターが必要だな。`gorillaMux` にしよう。」**  
- **「このルーターは、Gorilla Muxフレームワークを使ってHTTPリクエストを処理する。」**  
- **「ルーターの初期化は `newGorillaMux` 関数で行おう。ロガー、データベース、バリデーター、ポート、タイムアウトを受け取る。」**  
- **「`Listen` メソッドでサーバーを起動しよう。HTTPサーバーの設定を行い、シグナルを受け取ってシャットダウンもできるようにする。」**  
- **「`setAppHandlers` メソッドでルーティングを設定しよう。各エンドポイントに対応するアクションを紐付ける。」**  
- **「`buildCreateTransferAction`、`buildFindAllTransferAction`、`buildCreateAccountAction`、`buildFindAllAccountAction`、`buildFindBalanceAccountAction` メソッドで各ユースケースをビルドしよう。依存関係を注入してアクションを作成する。」**  
- **「`healthcheck` メソッドでヘルスチェックエンドポイントを設定しよう。サーバーの状態を確認できるようにする。」**  
- **「これで、HTTPリクエストの処理が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「Gorilla Muxフレームワークを使うことで、HTTPリクエストの処理を簡単に実装できる。」**  
- **「ルーターの初期化関数で依存関係を注入することで、テストしやすくなる。」**  
- **「`Listen` メソッドでサーバーの起動とシャットダウンを制御することで、リソースの管理がしやすくなる。」**  
- **「`setAppHandlers` メソッドでルーティングを設定することで、エンドポイントの追加や変更が容易になる。」**  
- **「各アクションをビルドするメソッドを用意することで、依存関係の注入が簡単になる。」**  
- **「ヘルスチェックエンドポイントを設定することで、サーバーの状態を監視しやすくなる。」**  
- **「これで、HTTPリクエストの処理が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的にエンドポイントを追加するときも、このルーターを拡張すればいい。拡張性が高まる。」**  
- **「これで、HTTPリクエストの処理が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


## infrastructure/validation/go_playground.go
```go
package validation

import (
	"errors"

	"github.com/gsabadini/go-clean-architecture/adapter/validator"

	"github.com/go-playground/locales/en"
	ut "github.com/go-playground/universal-translator"
	go_playground "github.com/go-playground/validator/v10"
	en_translations "github.com/go-playground/validator/v10/translations/en"
)

type goPlayground struct {
	validator *go_playground.Validate
	translate ut.Translator
	err       error
	msg       []string
}

func NewGoPlayground() (validator.Validator, error) {
	var (
		language         = en.New()
		uni              = ut.New(language, language)
		translate, found = uni.GetTranslator("en")
	)

	if !found {
		return nil, errors.New("translator not found")
	}

	v := go_playground.New()
	if err := en_translations.RegisterDefaultTranslations(v, translate); err != nil {
		return nil, errors.New("translator not found")
	}

	return &goPlayground{validator: v, translate: translate}, nil
}

func (g *goPlayground) Validate(i interface{}) error {
	if len(g.msg) > 0 {
		g.msg = nil
	}

	g.err = g.validator.Struct(i)
	if g.err != nil {
		return g.err
	}

	return nil
}

func (g *goPlayground) Messages() []string {
	if g.err != nil {
		for _, err := range g.err.(go_playground.ValidationErrors) {
			g.msg = append(g.msg, err.Translate(g.translate))
		}
	}

	return g.msg
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/bdeac963-cbe9-422e-84db-db29a10f2d4c.png)

### `infrastructure/validation/go_playground.go` を定義するときのキモチ 
- **「バリデーションの実装が必要だな。`goPlayground` にしよう。」**  
- **「このバリデーションは、Go Playgroundの `validator` パッケージを使って入力データを検証する。」**  
- **「`NewGoPlayground` 関数でバリデーションを初期化しよう。英語の翻訳も設定する。」**  
- **「`Validate` メソッドで入力データを検証しよう。エラーがあれば返す。」**  
- **「`Messages` メソッドでエラーメッセージを取得しよう。翻訳されたメッセージを返す。」**  
- **「これで、入力データの検証が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「Go Playgroundの `validator` パッケージを使うことで、入力データの検証を簡単に実装できる。」**  
- **「英語の翻訳を設定することで、エラーメッセージをユーザーにわかりやすく表示できる。」**  
- **「`Validate` メソッドで入力データを検証することで、無効なデータがシステムに渡るのを防ぐ。」**  
- **「`Messages` メソッドでエラーメッセージを取得することで、ユーザーにフィードバックを提供できる。」**  
- **「これで、入力データの検証が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のバリデーションパッケージを使うときも、このコンポーネントを拡張すればいい。拡張性が高まる。」**  
- **「これで、入力データの検証が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


## infrastructure/log/zap.go
```go
package log

import (
	"github.com/gsabadini/go-clean-architecture/adapter/logger"
	"go.uber.org/zap"
)

type zapLogger struct {
	logger *zap.SugaredLogger
}

func NewZapLogger() (logger.Logger, error) {
	log, err := zap.NewProduction()
	if err != nil {
		return nil, err
	}

	sugar := log.Sugar()
	defer log.Sync()

	return &zapLogger{logger: sugar}, nil
}

func (l *zapLogger) Infof(format string, args ...interface{}) {
	l.logger.Infof(format, args...)
}

func (l *zapLogger) Warnf(format string, args ...interface{}) {
	l.logger.Warnf(format, args...)
}

func (l *zapLogger) Errorf(format string, args ...interface{}) {
	l.logger.Errorf(format, args...)
}

func (l *zapLogger) Fatalln(args ...interface{}) {
	l.logger.Fatal(args)
}

func (l *zapLogger) WithFields(fields logger.Fields) logger.Logger {
	var f = make([]interface{}, 0)
	for index, field := range fields {
		f = append(f, index)
		f = append(f, field)
	}

	log := l.logger.With(f...)
	return &zapLogger{logger: log}
}

func (l *zapLogger) WithError(err error) logger.Logger {
	var log = l.logger.With(err.Error())
	return &zapLogger{logger: log}
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/f7abf24f-f862-423c-9999-2eccf7b32e58.png)

### `infrastructure/log/zap.go` を定義するときのキモチ 
- **「ロギングの実装が必要だな。`zapLogger` にしよう。」**  
- **「このロガーは、Zapパッケージを使ってログを記録する。」**  
- **「`NewZapLogger` 関数でロガーを初期化しよう。Zapのプロダクション設定を使う。」**  
- **「`Infof`、`Warnf`、`Errorf`、`Fatalln` メソッドでログを記録しよう。フォーマット付きのログ記録ができるようにする。」**  
- **「`WithFields` メソッドで追加のフィールドをログに含められるようにしよう。これでコンテキストを追加できる。」**  
- **「`WithError` メソッドでエラーをログに含められるようにしよう。これでエラーの詳細を記録できる。」**  
- **「これで、ロギングが独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「Zapパッケージを使うことで、高速で構造化されたログ記録ができる。」**  
- **「`NewZapLogger` 関数でロガーを初期化することで、ログの設定を一元管理できる。」**  
- **「`Infof`、`Warnf`、`Errorf`、`Fatalln` メソッドを用意することで、ログレベルごとの記録ができる。」**  
- **「`WithFields` メソッドで追加のフィールドをログに含められるようにすることで、デバッグや監視がしやすくなる。」**  
- **「`WithError` メソッドでエラーをログに含められるようにすることで、エラーの追跡が容易になる。」**  
- **「これで、ロギングが独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のロギングパッケージを使うときも、このコンポーネントを拡張すればいい。拡張性が高まる。」**  
- **「これで、ロギングが抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

## infrastructure/log/logrus.go
```go
package log

import (
	"github.com/gsabadini/go-clean-architecture/adapter/logger"
	"github.com/sirupsen/logrus"
)

type logrusLogger struct {
	logger *logrus.Logger
}

func NewLogrusLogger() logger.Logger {
	log := logrus.New()
	log.SetFormatter(&logrus.JSONFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
	})

	return &logrusLogger{logger: log}
}

func (l *logrusLogger) Infof(format string, args ...interface{}) {
	l.logger.Infof(format, args...)
}

func (l *logrusLogger) Warnf(format string, args ...interface{}) {
	l.logger.Warnf(format, args...)
}

func (l *logrusLogger) Errorf(format string, args ...interface{}) {
	l.logger.Errorf(format, args...)
}

func (l *logrusLogger) Fatalln(args ...interface{}) {
	l.logger.Fatalln(args...)
}

func (l *logrusLogger) WithFields(fields logger.Fields) logger.Logger {
	return &logrusLogEntry{
		entry: l.logger.WithFields(convertToLogrusFields(fields)),
	}
}

func (l *logrusLogger) WithError(err error) logger.Logger {
	return &logrusLogEntry{
		entry: l.logger.WithError(err),
	}
}

type logrusLogEntry struct {
	entry *logrus.Entry
}

func (l *logrusLogEntry) Infof(format string, args ...interface{}) {
	l.entry.Infof(format, args...)
}

func (l *logrusLogEntry) Warnf(format string, args ...interface{}) {
	l.entry.Warnf(format, args...)
}

func (l *logrusLogEntry) Errorf(format string, args ...interface{}) {
	l.entry.Errorf(format, args...)
}

func (l *logrusLogEntry) Fatalln(args ...interface{}) {
	l.entry.Fatalln(args...)
}

func (l *logrusLogEntry) WithFields(fields logger.Fields) logger.Logger {
	return &logrusLogEntry{
		entry: l.entry.WithFields(convertToLogrusFields(fields)),
	}
}

func (l *logrusLogEntry) WithError(err error) logger.Logger {
	return &logrusLogEntry{
		entry: l.entry.WithError(err),
	}
}

func convertToLogrusFields(fields logger.Fields) logrus.Fields {
	logrusFields := logrus.Fields{}
	for index, field := range fields {
		logrusFields[index] = field
	}

	return logrusFields
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/9da27a0c-c884-4752-aa5d-7e36ddb877a7.png)

### `infrastructure/log/logrus.go` を定義するときのキモチ 
- **「ロギングの実装が必要だな。`logrusLogger` にしよう。」**  
- **「このロガーは、Logrusパッケージを使ってログを記録する。」**  
- **「`NewLogrusLogger` 関数でロガーを初期化しよう。LogrusのJSONフォーマットを使う。」**  
- **「`Infof`、`Warnf`、`Errorf`、`Fatalln` メソッドでログを記録しよう。フォーマット付きのログ記録ができるようにする。」**  
- **「`WithFields` メソッドで追加のフィールドをログに含められるようにしよう。これでコンテキストを追加できる。」**  
- **「`WithError` メソッドでエラーをログに含められるようにしよう。これでエラーの詳細を記録できる。」**  
- **「`logrusLogEntry` 構造体も定義しよう。ログエントリの操作を担当する。」**  
- **「これで、ロギングが独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「Logrusパッケージを使うことで、柔軟で構造化されたログ記録ができる。」**  
- **「`NewLogrusLogger` 関数でロガーを初期化することで、ログの設定を一元管理できる。」**  
- **「`Infof`、`Warnf`、`Errorf`、`Fatalln` メソッドを用意することで、ログレベルごとの記録ができる。」**  
- **「`WithFields` メソッドで追加のフィールドをログに含められるようにすることで、デバッグや監視がしやすくなる。」**  
- **「`WithError` メソッドでエラーをログに含められるようにすることで、エラーの追跡が容易になる。」**  
- **「`logrusLogEntry` 構造体を定義することで、ログエントリの操作を抽象化する。」**  
- **「これで、ロギングが独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のロギングパッケージを使うときも、このコンポーネントを拡張すればいい。拡張性が高まる。」**  
- **「これで、ロギングが抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

## adapter/repository/account_mongodb.go
```go
package repository

import (
	"context"
	"time"

	"github.com/gsabadini/go-clean-architecture/domain"
	"github.com/pkg/errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

type accountBSON struct {
	ID        string    `bson:"id"`
	Name      string    `bson:"name"`
	CPF       string    `bson:"cpf"`
	Balance   int64     `bson:"balance"`
	CreatedAt time.Time `bson:"created_at"`
}

type AccountNoSQL struct {
	collectionName string
	db             NoSQL
}

func NewAccountNoSQL(db NoSQL) AccountNoSQL {
	return AccountNoSQL{
		db:             db,
		collectionName: "accounts",
	}
}

func (a AccountNoSQL) Create(ctx context.Context, account domain.Account) (domain.Account, error) {
	var accountBSON = accountBSON{
		ID:        account.ID().String(),
		Name:      account.Name(),
		CPF:       account.CPF(),
		Balance:   account.Balance().Int64(),
		CreatedAt: account.CreatedAt(),
	}

	if err := a.db.Store(ctx, a.collectionName, accountBSON); err != nil {
		return domain.Account{}, errors.Wrap(err, "error creating account")
	}

	return account, nil
}

func (a AccountNoSQL) UpdateBalance(ctx context.Context, ID domain.AccountID, balance domain.Money) error {
	var (
		query  = bson.M{"id": ID}
		update = bson.M{"$set": bson.M{"balance": balance}}
	)

	if err := a.db.Update(ctx, a.collectionName, query, update); err != nil {
		switch err {
		case mongo.ErrNilDocument:
			return errors.Wrap(domain.ErrAccountNotFound, "error updating account balance")
		default:
			return errors.Wrap(err, "error updating account balance")
		}
	}

	return nil
}

func (a AccountNoSQL) FindAll(ctx context.Context) ([]domain.Account, error) {
	var accountsBSON = make([]accountBSON, 0)

	if err := a.db.FindAll(ctx, a.collectionName, bson.M{}, &accountsBSON); err != nil {
		switch err {
		case mongo.ErrNilDocument:
			return []domain.Account{}, errors.Wrap(domain.ErrAccountNotFound, "error listing accounts")
		default:
			return []domain.Account{}, errors.Wrap(err, "error listing accounts")
		}
	}

	var accounts = make([]domain.Account, 0)

	for _, accountBSON := range accountsBSON {
		var account = domain.NewAccount(
			domain.AccountID(accountBSON.ID),
			accountBSON.Name,
			accountBSON.CPF,
			domain.Money(accountBSON.Balance),
			accountBSON.CreatedAt,
		)

		accounts = append(accounts, account)
	}

	return accounts, nil
}

func (a AccountNoSQL) FindByID(ctx context.Context, ID domain.AccountID) (domain.Account, error) {
	var (
		accountBSON = &accountBSON{}
		query       = bson.M{"id": ID}
	)

	if err := a.db.FindOne(ctx, a.collectionName, query, nil, accountBSON); err != nil {
		switch err {
		case mongo.ErrNoDocuments:
			return domain.Account{}, domain.ErrAccountNotFound
		default:
			return domain.Account{}, errors.Wrap(err, "error fetching account")
		}
	}

	return domain.NewAccount(
		domain.AccountID(accountBSON.ID),
		accountBSON.Name,
		accountBSON.CPF,
		domain.Money(accountBSON.Balance),
		accountBSON.CreatedAt,
	), nil
}

func (a AccountNoSQL) FindBalance(ctx context.Context, ID domain.AccountID) (domain.Account, error) {
	var (
		accountBSON = &accountBSON{}
		query       = bson.M{"id": ID}
		projection  = bson.M{"balance": 1, "_id": 0}
	)

	if err := a.db.FindOne(ctx, a.collectionName, query, projection, accountBSON); err != nil {
		switch err {
		case mongo.ErrNoDocuments:
			return domain.Account{}, domain.ErrAccountNotFound
		default:
			return domain.Account{}, errors.Wrap(err, "error fetching account balance")
		}
	}

	return domain.NewAccountBalance(domain.Money(accountBSON.Balance)), nil
}

```

対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/d719974f-2079-4f54-8eae-25bb2fe05f36.png)

### NoSQL側のAccountRepositoryの実装
AccountNoSQLオブジェクトはAccountRepositoryインタフェースを暗黙に実装している。
以下の記事を参照。

https://qiita.com/koichi2426/questions/d18db30f9b4ca7de6b7b

### `AccountNoSQL` を定義するときのキモチ
- **「MongoDBを使ったアカウントのリポジトリが必要だな。`AccountNoSQL` にしよう。」**  
- **「このリポジトリは、アカウントの永続化と取得を担当する。」**  
- **「MongoDBのコレクション名は `accounts` にしよう。これでデータを整理しやすくなる。」**  
- **「ドメイン層の `Account` を MongoDB に保存するために、`accountBSON` 構造体を定義しよう。」**  
- **`accountBSON` は MongoDB のドキュメント形式に合わせる。ID、Name、CPF、Balance、CreatedAt をフィールドに持つ。」**  
- **「`Create` メソッドでアカウントを作成しよう。ドメイン層の `Account` を `accountBSON` に変換して保存する。」**  
- **「`UpdateBalance` メソッドでアカウントの残高を更新しよう。MongoDBの `$set` を使って更新する。」**  
- **「`FindAll` メソッドで全アカウントを取得しよう。MongoDBから取得したデータをドメイン層の `Account` に変換する。」**  
- **「`FindByID` メソッドで特定のアカウントを取得しよう。IDで検索して、ドメイン層の `Account` に変換する。」**  
- **「`FindBalance` メソッドでアカウントの残高を取得しよう。プロジェクションを使って必要なフィールドだけ取得する。」**  
- **「エラーハンドリングはしっかりやろう。MongoDBのエラーをドメイン層のエラーに変換する。」**  
- **「これで、アカウントの永続化と取得が MongoDB を使って実装できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「ドメイン層の `Account` を MongoDB のドキュメント形式に変換することで、データの整合性を保つ。」**  
- **「MongoDBの操作を抽象化した `NoSQL` インタフェースを使うことで、データベースの実装に依存しないようにする。」**  
- **「エラーハンドリングをしっかり行うことで、ユーザーにわかりやすいエラーメッセージを返す。」**  
- **「`FindBalance` メソッドでプロジェクションを使うことで、必要なデータだけ取得してパフォーマンスを向上させる。」**  
- **「これで、アカウントの永続化と取得が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的にデータベースを変更するときも、このリポジトリを拡張すればいい。拡張性が高まる。」**  
- **「これで、アカウントのデータアクセスが MongoDB を使って実装できた。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**



## adapter/repository/account_postgres.go
```go
package repository

import (
	"context"
	"database/sql"
	"time"

	"github.com/gsabadini/go-clean-architecture/domain"
	"github.com/pkg/errors"
)

type AccountSQL struct {
	db SQL
}

func NewAccountSQL(db SQL) AccountSQL {
	return AccountSQL{
		db: db,
	}
}

func (a AccountSQL) Create(ctx context.Context, account domain.Account) (domain.Account, error) {
	var query = `
		INSERT INTO 
			accounts (id, name, cpf, balance, created_at)
		VALUES 
			($1, $2, $3, $4, $5)
	`

	if err := a.db.ExecuteContext(
		ctx,
		query,
		account.ID(),
		account.Name(),
		account.CPF(),
		account.Balance(),
		account.CreatedAt(),
	); err != nil {
		return domain.Account{}, errors.Wrap(err, "error creating account")
	}

	return account, nil
}

func (a AccountSQL) UpdateBalance(ctx context.Context, ID domain.AccountID, balance domain.Money) error {
	tx, ok := ctx.Value("TransactionContextKey").(Tx)
	if !ok {
		var err error
		tx, err = a.db.BeginTx(ctx)
		if err != nil {
			return errors.Wrap(err, "error updating account balance")
		}
	}

	query := "UPDATE accounts SET balance = $1 WHERE id = $2"

	if err := tx.ExecuteContext(ctx, query, balance, ID); err != nil {
		return errors.Wrap(err, "error updating account balance")
	}

	return nil
}

func (a AccountSQL) FindAll(ctx context.Context) ([]domain.Account, error) {
	var query = "SELECT * FROM accounts"

	rows, err := a.db.QueryContext(ctx, query)
	if err != nil {
		return []domain.Account{}, errors.Wrap(err, "error listing accounts")
	}

	var accounts = make([]domain.Account, 0)
	for rows.Next() {
		var (
			ID        string
			name      string
			CPF       string
			balance   int64
			createdAt time.Time
		)

		if err = rows.Scan(&ID, &name, &CPF, &balance, &createdAt); err != nil {
			return []domain.Account{}, errors.Wrap(err, "error listing accounts")
		}

		accounts = append(accounts, domain.NewAccount(
			domain.AccountID(ID),
			name,
			CPF,
			domain.Money(balance),
			createdAt,
		))
	}
	defer rows.Close()

	if err = rows.Err(); err != nil {
		return []domain.Account{}, err
	}

	return accounts, nil
}

func (a AccountSQL) FindByID(ctx context.Context, ID domain.AccountID) (domain.Account, error) {
	tx, ok := ctx.Value("TransactionContextKey").(Tx)
	if !ok {
		var err error
		tx, err = a.db.BeginTx(ctx)
		if err != nil {
			return domain.Account{}, errors.Wrap(err, "error find account by id")
		}
	}

	var (
		query     = "SELECT * FROM accounts WHERE id = $1 LIMIT 1 FOR NO KEY UPDATE"
		id        string
		name      string
		CPF       string
		balance   int64
		createdAt time.Time
	)

	err := tx.QueryRowContext(ctx, query, ID).Scan(&id, &name, &CPF, &balance, &createdAt)
	switch {
	case err == sql.ErrNoRows:
		return domain.Account{}, domain.ErrAccountNotFound
	default:
		return domain.NewAccount(
			domain.AccountID(id),
			name,
			CPF,
			domain.Money(balance),
			createdAt,
		), err
	}
}

func (a AccountSQL) FindBalance(ctx context.Context, ID domain.AccountID) (domain.Account, error) {
	var (
		query   = "SELECT balance FROM accounts WHERE id = $1"
		balance int64
	)

	err := a.db.QueryRowContext(ctx, query, ID).Scan(&balance)
	switch {
	case err == sql.ErrNoRows:
		return domain.Account{}, domain.ErrAccountNotFound
	default:
		return domain.NewAccountBalance(domain.Money(balance)), err
	}
}

```

対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/a8073b2c-eb50-4805-9d1e-7a818e10235a.png)

### SQL側のAccountRepositoryの実装
AccountNoSQLオブジェクトはAccountRepositoryインタフェースを暗黙に実装している。
以下の記事を参照。

https://qiita.com/koichi2426/questions/d18db30f9b4ca7de6b7b

### `AccountNoSQL` を定義するときのキモチ
- **「PostgreSQLを使ったアカウントのリポジトリが必要だな。`AccountSQL` にしよう。」**  
- **「このリポジトリは、アカウントの永続化と取得を担当する。」**  
- **「SQLクエリを使ってアカウントのデータを操作する。`INSERT`、`UPDATE`、`SELECT` を使う。」**  
- **「`Create` メソッドでアカウントを作成しよう。ドメイン層の `Account` を SQL に変換して保存する。」**  
- **「`UpdateBalance` メソッドでアカウントの残高を更新しよう。トランザクションを使ってデータの整合性を保つ。」**  
- **「`FindAll` メソッドで全アカウントを取得しよう。SQLクエリで取得したデータをドメイン層の `Account` に変換する。」**  
- **「`FindByID` メソッドで特定のアカウントを取得しよう。IDで検索して、ドメイン層の `Account` に変換する。」**  
- **「`FindBalance` メソッドでアカウントの残高を取得しよう。必要なフィールドだけ取得する。」**  
- **「エラーハンドリングはしっかりやろう。SQLのエラーをドメイン層のエラーに変換する。」**  
- **「これで、アカウントの永続化と取得が PostgreSQL を使って実装できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「ドメイン層の `Account` を SQL のテーブル形式に変換することで、データの整合性を保つ。」**  
- **「SQLの操作を抽象化した `SQL` インタフェースを使うことで、データベースの実装に依存しないようにする。」**  
- **「トランザクションを使ってデータの整合性を保つ。特に `UpdateBalance` では重要だ。」**  
- **「エラーハンドリングをしっかり行うことで、ユーザーにわかりやすいエラーメッセージを返す。」**  
- **「`FindBalance` メソッドで必要なフィールドだけ取得することで、パフォーマンスを向上させる。」**  
- **「これで、アカウントの永続化と取得が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的にデータベースを変更するときも、このリポジトリを拡張すればいい。拡張性が高まる。」**  
- **「これで、アカウントのデータアクセスが PostgreSQL を使って実装できた。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

## adapter/repository/nosql.go
```go
package repository

import "context"

type NoSQL interface {
	Store(context.Context, string, interface{}) error
	Update(context.Context, string, interface{}, interface{}) error
	FindAll(context.Context, string, interface{}, interface{}) error
	FindOne(context.Context, string, interface{}, interface{}, interface{}) error
	StartSession() (Session, error)
}

type Session interface {
	WithTransaction(context.Context, func(context.Context) error) error
	EndSession(context.Context)
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/cff4dae1-e8e8-4e16-ae03-24197a257fd5.png)

### なぜ `NoSQL< i >` を定義するのか？
インフラ層での特定のNoSQLの実装の受け皿を用意するためであり、`adapter/repository/account_mongodb.go`のAccountSQLオブジェクトが所有する。

### `NoSQL< i >` を定義するときのキモチ 
- **「NoSQLデータベースの操作を抽象化するインタフェースが必要だな。`NoSQL` にしよう。」**  
- **「このインタフェースは、NoSQLデータベースに対する基本的な操作を提供する。」**  
- **「`Store` メソッドでデータを保存しよう。コレクション名とデータを受け取る。」**  
- **「`Update` メソッドでデータを更新しよう。クエリと更新データを受け取る。」**  
- **「`FindAll` メソッドで全データを取得しよう。コレクション名とクエリ、結果を受け取る。」**  
- **「`FindOne` メソッドで特定のデータを取得しよう。コレクション名、クエリ、プロジェクション、結果を受け取る。」**  
- **「トランザクションをサポートするために、`StartSession` メソッドを用意しよう。セッションを開始して、トランザクションを実行できるようにする。」**  
- **「`Session` インタフェースも定義しよう。トランザクションの実行とセッションの終了を担当する。」**  
- **「これで、NoSQLデータベースの操作が抽象化された。具体的な実装に依存しなくなる。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に別のNoSQLデータベースを使うときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「これで、NoSQLデータベースの操作が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「NoSQLデータベースの操作を抽象化することで、アプリケーションが特定のデータベースに依存しなくなる。」**  
- **「トランザクションをサポートすることで、データの整合性を保つことができる。」**  
- **「`Store`、`Update`、`FindAll`、`FindOne` メソッドを用意することで、基本的なCRUD操作をカバーする。」**  
- **「`StartSession` メソッドでトランザクションを実行できるようにすることで、複雑な操作もサポートする。」**  
- **「これで、NoSQLデータベースの操作が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のNoSQLデータベースを使うときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「これで、NoSQLデータベースの操作が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

## adapter/repository/sql.go
```go
package repository

import "context"

type SQL interface {
	ExecuteContext(context.Context, string, ...interface{}) error
	QueryContext(context.Context, string, ...interface{}) (Rows, error)
	QueryRowContext(context.Context, string, ...interface{}) Row
	BeginTx(ctx context.Context) (Tx, error)
}

type Rows interface {
	Scan(dest ...interface{}) error
	Next() bool
	Err() error
	Close() error
}

type Row interface {
	Scan(dest ...interface{}) error
}

type Tx interface {
	ExecuteContext(context.Context, string, ...interface{}) error
	QueryContext(context.Context, string, ...interface{}) (Rows, error)
	QueryRowContext(context.Context, string, ...interface{}) Row
	Commit() error
	Rollback() error
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/42ab6b59-72b5-4814-9db1-c97ab4e438b7.png)

### より詳しい解説はこちら
https://qiita.com/koichi2426/items/3ebc9de208296d9b2317

### なぜ `SQL< i >` を定義するのか？
インフラ層での特定のSQLの実装の受け皿を用意するためであり、`adapter/repository/account_postgres.go`のAccountSQLオブジェクトが所有する。

### `SQL< i >` を定義するときのキモチ
- **「SQLデータベースの操作を抽象化するインタフェースが必要だな。`SQL` にしよう。」**  
- **「このインタフェースは、SQLデータベースに対する基本的な操作を提供する。」**  
- **「`ExecuteContext` メソッドでクエリを実行しよう。コンテキスト、クエリ、パラメータを受け取る。」**  
- **「`QueryContext` メソッドで複数行のデータを取得しよう。コンテキスト、クエリ、パラメータを受け取り、`Rows` を返す。」**  
- **「`QueryRowContext` メソッドで単一行のデータを取得しよう。コンテキスト、クエリ、パラメータを受け取り、`Row` を返す。」**  
- **「トランザクションをサポートするために、`BeginTx` メソッドを用意しよう。トランザクションを開始して、`Tx` インタフェースを返す。」**  
- **「`Rows` インタフェースも定義しよう。複数行のデータをスキャンするためのメソッドを提供する。」**  
- **「`Row` インタフェースも定義しよう。単一行のデータをスキャンするためのメソッドを提供する。」**  
- **「`Tx` インタフェースも定義しよう。トランザクション内でのクエリ実行、コミット、ロールバックを担当する。」**  
- **「これで、SQLデータベースの操作が抽象化された。具体的な実装に依存しなくなる。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に別のSQLデータベースを使うときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「これで、SQLデータベースの操作が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「SQLデータベースの操作を抽象化することで、アプリケーションが特定のデータベースに依存しなくなる。」**  
- **「トランザクションをサポートすることで、データの整合性を保つことができる。」**  
- **「`ExecuteContext`、`QueryContext`、`QueryRowContext` メソッドを用意することで、基本的なCRUD操作をカバーする。」**  
- **「`BeginTx` メソッドでトランザクションを開始できるようにすることで、複雑な操作もサポートする。」**  
- **「`Rows` と `Row` インタフェースを定義することで、データの取得とスキャンを抽象化する。」**  
- **「`Tx` インタフェースを定義することで、トランザクション内での操作を抽象化する。」**  
- **「これで、SQLデータベースの操作が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のSQLデータベースを使うときも、このインタフェースを満たす新しい実装を作ればいい。拡張性が高まる。」**  
- **「これで、SQLデータベースの操作が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


## infrastructure/database/mongo_handler.go
```go
package database

import (
	"context"
	"fmt"
	"github.com/gsabadini/go-clean-architecture/adapter/repository"
	"log"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type mongoHandler struct {
	db     *mongo.Database
	client *mongo.Client
}

func NewMongoHandler(c *config) (*mongoHandler, error) {
	ctx, cancel := context.WithTimeout(context.Background(), c.ctxTimeout)
	defer cancel()

	uri := fmt.Sprintf(
		"%s://%s:%s@mongodb-primary,mongodb-secondary,mongodb-arbiter/?replicaSet=replicaset",
		c.host,
		c.user,
		c.password,
	)

	clientOpts := options.Client().ApplyURI(uri)
	client, err := mongo.Connect(ctx, clientOpts)
	if err != nil {
		log.Fatal(err)
	}

	err = client.Ping(ctx, nil)
	if err != nil {
		log.Fatal(err)
	}

	return &mongoHandler{
		db:     client.Database(c.database),
		client: client,
	}, nil
}

func (mgo mongoHandler) Store(ctx context.Context, collection string, data interface{}) error {
	if _, err := mgo.db.Collection(collection).InsertOne(ctx, data); err != nil {
		return err
	}

	return nil
}

func (mgo mongoHandler) Update(ctx context.Context, collection string, query interface{}, update interface{}) error {
	if _, err := mgo.db.Collection(collection).UpdateOne(ctx, query, update); err != nil {
		return err
	}

	return nil
}

func (mgo mongoHandler) FindAll(ctx context.Context, collection string, query interface{}, result interface{}) error {
	cur, err := mgo.db.Collection(collection).Find(ctx, query)
	if err != nil {
		return err
	}

	defer cur.Close(ctx)
	if err = cur.All(ctx, result); err != nil {
		return err
	}

	if err := cur.Err(); err != nil {
		return err
	}

	return nil
}

func (mgo mongoHandler) FindOne(
	ctx context.Context,
	collection string,
	query interface{},
	projection interface{},
	result interface{},
) error {
	var err = mgo.db.Collection(collection).
		FindOne(
			ctx,
			query,
			options.FindOne().SetProjection(projection),
		).Decode(result)
	if err != nil {
		return err
	}

	return nil
}

func (mgo *mongoHandler) StartSession() (repository.Session, error) {
	session, err := mgo.client.StartSession()
	if err != nil {
		log.Fatal(err)
	}

	return newMongoHandlerSession(session), nil
}

type mongoDBSession struct {
	session mongo.Session
}

func newMongoHandlerSession(session mongo.Session) *mongoDBSession {
	return &mongoDBSession{session: session}
}

func (m *mongoDBSession) WithTransaction(ctx context.Context, fn func(context.Context) error) error {
	callback := func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := fn(sessCtx)
		if err != nil {
			return nil, err
		}
		return nil, nil
	}

	_, err := m.session.WithTransaction(ctx, callback)
	if err != nil {
		return err
	}

	return nil
}

func (m *mongoDBSession) EndSession(ctx context.Context) {
	m.session.EndSession(ctx)
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/42253237-c2a8-460d-b034-a13de4e74c3b.png)


### 暗黙のインタフェース実装
mongoHandlerはNoSQLインタフェースを暗に実装している。理屈は先ほどのAccountRepositoryインタフェースの実装と同じ。

https://qiita.com/koichi2426/questions/d18db30f9b4ca7de6b7b

### `mongoHandler` を定義するときのキモチ
- **「MongoDBとの接続と操作を担当するハンドラが必要だな。`mongoHandler` にしよう。」**  
- **「このハンドラは、MongoDBに対する基本的な操作を提供する。」**  
- **「MongoDBの接続情報は設定ファイルから取得しよう。ホスト、ユーザー、パスワード、データベース名が必要だ。」**  
- **「`NewMongoHandler` 関数でMongoDBに接続しよう。接続URIを組み立てて、クライアントを作成する。」**  
- **「接続が成功したら、データベースとクライアントを保持しておこう。これで後で使える。」**  
- **「`Store` メソッドでデータを保存しよう。コレクション名とデータを受け取る。」**  
- **「`Update` メソッドでデータを更新しよう。コレクション名、クエリ、更新データを受け取る。」**  
- **「`FindAll` メソッドで全データを取得しよう。コレクション名、クエリ、結果を受け取る。」**  
- **「`FindOne` メソッドで特定のデータを取得しよう。コレクション名、クエリ、プロジェクション、結果を受け取る。」**  
- **「トランザクションをサポートするために、`StartSession` メソッドを用意しよう。セッションを開始して、トランザクションを実行できるようにする。」**  
- **「`mongoDBSession` 構造体も定義しよう。トランザクションの実行とセッションの終了を担当する。」**  
- **「これで、MongoDBの操作が抽象化された。具体的な実装に依存しなくなる。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に別のNoSQLデータベースを使うときも、このハンドラを拡張すればいい。拡張性が高まる。」**  
- **「これで、MongoDBの操作が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「MongoDBの接続情報を設定ファイルから取得することで、柔軟性を高める。」**  
- **「`Store`、`Update`、`FindAll`、`FindOne` メソッドを用意することで、基本的なCRUD操作をカバーする。」**  
- **「トランザクションをサポートすることで、データの整合性を保つことができる。」**  
- **「`StartSession` メソッドでトランザクションを実行できるようにすることで、複雑な操作もサポートする。」**  
- **「`mongoDBSession` 構造体を定義することで、トランザクションの実行とセッションの終了を抽象化する。」**  
- **「これで、MongoDBの操作が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のNoSQLデータベースを使うときも、このハンドラを拡張すればいい。拡張性が高まる。」**  
- **「これで、MongoDBの操作が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**

## infrastructure/database/postgres_handler.go
```go
package database

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	"github.com/gsabadini/go-clean-architecture/adapter/repository"

	_ "github.com/lib/pq"
)

type postgresHandler struct {
	db *sql.DB
}

func NewPostgresHandler(c *config) (*postgresHandler, error) {
	var ds = fmt.Sprintf(
		"host=%s port=%s user=%s dbname=%s sslmode=disable password=%s",
		c.host,
		c.port,
		c.user,
		c.database,
		c.password,
	)

	fmt.Println(ds)
	db, err := sql.Open(c.driver, ds)
	if err != nil {
		return &postgresHandler{}, err
	}

	err = db.Ping()
	if err != nil {
		log.Fatalln(err)
	}

	return &postgresHandler{db: db}, nil
}

func (p postgresHandler) BeginTx(ctx context.Context) (repository.Tx, error) {
	tx, err := p.db.BeginTx(ctx, &sql.TxOptions{})
	if err != nil {
		return postgresTx{}, err
	}

	return newPostgresTx(tx), nil
}

func (p postgresHandler) ExecuteContext(ctx context.Context, query string, args ...interface{}) error {
	_, err := p.db.ExecContext(ctx, query, args...)
	if err != nil {
		return err
	}

	return nil
}

func (p postgresHandler) QueryContext(ctx context.Context, query string, args ...interface{}) (repository.Rows, error) {
	rows, err := p.db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}

	row := newPostgresRows(rows)

	return row, nil
}

func (p postgresHandler) QueryRowContext(ctx context.Context, query string, args ...interface{}) repository.Row {
	row := p.db.QueryRowContext(ctx, query, args...)

	return newPostgresRow(row)
}

type postgresRow struct {
	row *sql.Row
}

func newPostgresRow(row *sql.Row) postgresRow {
	return postgresRow{row: row}
}

func (pr postgresRow) Scan(dest ...interface{}) error {
	if err := pr.row.Scan(dest...); err != nil {
		return err
	}

	return nil
}

type postgresRows struct {
	rows *sql.Rows
}

func newPostgresRows(rows *sql.Rows) postgresRows {
	return postgresRows{rows: rows}
}

func (pr postgresRows) Scan(dest ...interface{}) error {
	if err := pr.rows.Scan(dest...); err != nil {
		return err
	}

	return nil
}

func (pr postgresRows) Next() bool {
	return pr.rows.Next()
}

func (pr postgresRows) Err() error {
	return pr.rows.Err()
}

func (pr postgresRows) Close() error {
	return pr.rows.Close()
}

type postgresTx struct {
	tx *sql.Tx
}

func newPostgresTx(tx *sql.Tx) postgresTx {
	return postgresTx{tx: tx}
}

func (p postgresTx) ExecuteContext(ctx context.Context, query string, args ...interface{}) error {
	_, err := p.tx.ExecContext(ctx, query, args...)
	if err != nil {
		return err
	}

	return nil
}

func (p postgresTx) QueryContext(ctx context.Context, query string, args ...interface{}) (repository.Rows, error) {
	rows, err := p.tx.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}

	row := newPostgresRows(rows)

	return row, nil
}

func (p postgresTx) QueryRowContext(ctx context.Context, query string, args ...interface{}) repository.Row {
	row := p.tx.QueryRowContext(ctx, query, args...)

	return newPostgresRow(row)
}

func (p postgresTx) Commit() error {
	return p.tx.Commit()
}

func (p postgresTx) Rollback() error {
	return p.tx.Rollback()
}

```
対応部分は赤枠部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/a20377ed-1c60-4e8f-a2b5-b35d76658bba.png)



### 暗黙のインタフェース実装
postgresHandlerはNoSQLインタフェースを暗に実装している。理屈は先ほどのAccountRepositoryインタフェースの実装と同じ。

https://qiita.com/koichi2426/questions/d18db30f9b4ca7de6b7b

### `postgresHandler` を定義するときのキモチ  
- **「PostgreSQLとの接続と操作を担当するハンドラが必要だな。`postgresHandler` にしよう。」**  
- **「このハンドラは、PostgreSQLに対する基本的な操作を提供する。」**  
- **「PostgreSQLの接続情報は設定ファイルから取得しよう。ホスト、ポート、ユーザー、データベース名、パスワードが必要だ。」**  
- **「`NewPostgresHandler` 関数でPostgreSQLに接続しよう。接続文字列を組み立てて、データベースに接続する。」**  
- **「接続が成功したら、データベースを保持しておこう。これで後で使える。」**  
- **「`ExecuteContext` メソッドでクエリを実行しよう。コンテキスト、クエリ、パラメータを受け取る。」**  
- **「`QueryContext` メソッドで複数行のデータを取得しよう。コンテキスト、クエリ、パラメータを受け取り、`Rows` を返す。」**  
- **「`QueryRowContext` メソッドで単一行のデータを取得しよう。コンテキスト、クエリ、パラメータを受け取り、`Row` を返す。」**  
- **「トランザクションをサポートするために、`BeginTx` メソッドを用意しよう。トランザクションを開始して、`Tx` インタフェースを返す。」**  
- **「`postgresRow`、`postgresRows`、`postgresTx` 構造体も定義しよう。データの取得とトランザクションの実行を担当する。」**  
- **「これで、PostgreSQLの操作が抽象化された。具体的な実装に依存しなくなる。」**  
- **「テストのときも、モックを使いやすくなる。インタフェースがあるから、実装を差し替えられる。」**  
- **「将来的に別のSQLデータベースを使うときも、このハンドラを拡張すればいい。拡張性が高まる。」**  
- **「これで、PostgreSQLの操作が独立したコンポーネントとして定義できた。クリーンだ。」**  
- **「まあ、必要になったらリファクタリングすればいいか。今はこれで十分だ。」**  

### 追加のキモチ  
- **「PostgreSQLの接続情報を設定ファイルから取得することで、柔軟性を高める。」**  
- **「`ExecuteContext`、`QueryContext`、`QueryRowContext` メソッドを用意することで、基本的なCRUD操作をカバーする。」**  
- **「トランザクションをサポートすることで、データの整合性を保つことができる。」**  
- **「`BeginTx` メソッドでトランザクションを開始できるようにすることで、複雑な操作もサポートする。」**  
- **「`postgresRow`、`postgresRows`、`postgresTx` 構造体を定義することで、データの取得とトランザクションの実行を抽象化する。」**  
- **「これで、PostgreSQLの操作が独立したコンポーネントとして定義できた。保守性も高い。」**  
- **「将来的に別のSQLデータベースを使うときも、このハンドラを拡張すればいい。拡張性が高まる。」**  
- **「これで、PostgreSQLの操作が抽象化された。クリーンだ。」**  
- **「まあ、足りないところはリファクタリングで直せばいいか。」**


# 参考資料
https://zenn.dev/castingone_dev/articles/77ecac84226521#golang-clean-architecture-banking-transfer

https://qiita.com/nrslib/items/a5f902c4defc83bd46b8

https://qiita.com/jin007/items/b4dc391a2e83eb999669