ようこそ！クリーンアーキテクチャ世界一周ツアーへ

皆さま、本日は「クリーンアーキテクチャ」という壮大なソフトウェアの世界を巡るツアーにご参加いただき、ありがとうございます！  
これから4つの不思議な“層の国”を旅してまいります。ガイドは私。エンジニアリングの世界をナビゲートするコンダクターです。では、旅を始めましょう！


# 🪄第一の目的地：**ドメイン層王国**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/934d2c55-9467-46e7-b049-ac6de3ddab99.png)

最初に訪れるのは、「仮想世界の創造主たち」が住むドメイン層王国。ここは、物語の世界や魔法の国、未来の宇宙都市さえもプログラムの力で再現された、想像力あふれる世界です。

この国の住人たちは、「ドメインモデル図」という地図を使って、自分たちの世界を可視化しています。解決したい問題領域に対する最適な構造を探求する、まさに創造の中心地です。

### 🎯具体例：エンティティ「User」とその振る舞い
```go
// domain/user.go
package domain

import (
    "errors"
)

type User struct {
    ID    string
    Name  string
    Email string
}

func (u *User) ChangeEmail(newEmail string) error {
    if !isValidEmail(newEmail) {
        return errors.New("invalid email format")
    }
    u.Email = newEmail
    return nil
}

func isValidEmail(email string) bool {
    return len(email) > 5 && // シンプルな例
        (email[len(email)-4:] == ".com" || email[len(email)-3:] == ".jp")
}

```

# 🎭第二の目的地：**ユースケース層シアター**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/172b5050-65a9-46ec-97e0-38e35da91d46.png)


さて、お次はドメイン層王国で築かれた仮想世界を舞台に、ドラマが繰り広げられるユースケース層シアターへと向かいましょう！

この劇場では、「どのように物語が動くのか」が脚本として記されています。
たとえば「ユーザーがボタンを押すと、どんな反応が返ってくるのか？」──そんなアプリケーションの具体的な流れが、ここで演出されているのです。

そして、このステージの舞台装置として使われているのが、なんとドメイン層王国の住人たちが作り上げた“仮想世界のふるまい”。
彼らの創造した魔法や仕組みを、私たち現実世界の演出家（開発者）はありがたく利用しながら、劇を成立させているのです。

このユースケース層はまさに、「仮想世界の力を借りて現実のニーズに応える舞台」──私たちはその公演の恩恵を存分に享受している観客でもあり、演出家でもあるのです。

### 🎯具体例：ユーザーのメールアドレス変更ユースケース
```go
// usecase/change_email.go
package usecase

import (
    "context"
    "example.com/project/domain"
)

type UserRepository interface {
    FindByID(ctx context.Context, id string) (*domain.User, error)
    Save(ctx context.Context, user *domain.User) error
}

type ChangeEmailUseCase struct {
    Repo UserRepository
}

func (uc *ChangeEmailUseCase) Execute(ctx context.Context, userID, newEmail string) error {
    user, err := uc.Repo.FindByID(ctx, userID)
    if err != nil {
        return err
    }

    if err := user.ChangeEmail(newEmail); err != nil {
        return err
    }

    return uc.Repo.Save(ctx, user)
}

```

# 🔄第三の目的地：**インターフェースアダプタ通訳センター**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/541348d2-1a2a-415a-9ffd-e14727558aed.png)


続いてやって来たのは、現実世界と仮想世界の橋渡しをしてくれるインターフェースアダプタ通訳センターです！

ここではControllerたちがユーザーの入力を翻訳し、Presenterたちが仮想世界からの返答を“私たちにも分かる言葉”に変換してくれます。まさに国際空港の通訳ブースのような場所！

さらに、データベースとの橋渡しをしてくれるGatewayたちも働いています。おかげで、複雑な内部構造に迷わずにすむのです。

### 🎯具体例：HTTP Controllerとデータ変換
```go
// interface/controller/user_controller.go
package controller

import (
    "net/http"
    "encoding/json"
    "example.com/project/usecase"
)

type ChangeEmailRequest struct {
    UserID   string `json:"user_id"`
    NewEmail string `json:"new_email"`
}

func ChangeEmailHandler(uc *usecase.ChangeEmailUseCase) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req ChangeEmailRequest
        _ = json.NewDecoder(r.Body).Decode(&req)

        err := uc.Execute(r.Context(), req.UserID, req.NewEmail)
        if err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        w.WriteHeader(http.StatusOK)
        w.Write([]byte("email changed"))
    }
}
```

# 🛠️最終目的地：**フレームワーク＆ドライバ市場**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868342/26910ab3-e1a4-4ece-8967-39513ceb7add.png)

旅の最後は、現実世界との接点である“道具の市場”──フレームワーク＆ドライバ層へとご案内します。

ここには、WebサーバやUIフレームワーク、データベースといった実行環境が所狭しと並んでおり、まさに開発者のためのバザール！

このマーケットにあるツールたちが、先ほどの通訳センターを通して、ユースケース層の動きを具体的なアプリとして実現してくれるのです。
### 🎯具体例：DBへの接続と実装
```go
// infrastructure/repo/user_repo.go
package repo

import (
    "context"
    "database/sql"
    "example.com/project/domain"
)

type UserRepo struct {
    DB *sql.DB
}

func (r *UserRepo) FindByID(ctx context.Context, id string) (*domain.User, error) {
    row := r.DB.QueryRowContext(ctx, "SELECT id, name, email FROM users WHERE id = ?", id)
    var user domain.User
    if err := row.Scan(&user.ID, &user.Name, &user.Email); err != nil {
        return nil, err
    }
    return &user, nil
}

func (r *UserRepo) Save(ctx context.Context, user *domain.User) error {
    _, err := r.DB.ExecContext(ctx, "UPDATE users SET email = ? WHERE id = ?", user.Email, user.ID)
    return err
}
```