【Goで学ぶコンピューターサイエンス】アーキテクチャの基礎

## 主要なアーキテクチャパターン

### 1. MVCアーキテクチャ
- **特徴**
    - Model（データ）、View（表示）、Controller（制御）の3層構造
- **メリット**
  - 責務が明確に分離され、保守性が高い
  - コードの再利用性が向上
  - テストが容易
- **デメリット**
  - Model、Controllerが肥大化しやすい

### 2. レイヤードアーキテクチャ
- **特徴**
    - プレゼンテーション層、ビジネスロジック層、データアクセス層などの階層構造
- **メリット**：
  - 関心事の分離が明確
  - 各層の独立した開発が可能
  - 保守性とスケーラビリティが高い
- **デメリット**
  - 層間の依存関係管理が複雑になる可能性
  - パフォーマンスへの影響（層間通信のオーバーヘッド）

### 3. クリーンアーキテクチャ
- **特徴**
    - ドメイン中心の設計、依存関係の方向が内側に向く
- **メリット**
  - ビジネスロジックが外部要因から保護される
  - テスタビリティが高い
  - フレームワークに依存しない設計
- **デメリット**
  - 学習曲線が急
  - 小規模プロジェクトでは複雑すぎる可能性

## 実装例
### MVCアーキテクチャの実装例
```model/user.go
package model

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}
```

```view/user_view.go
package view

import (
	"encoding/json"
	"go-cs/model"
)

type UserView struct {
	User *model.User
}

func (v *UserView) RenderJSON() ([]byte, error) {
	return json.Marshal(v.User)
}
```

```controller/user_controller.go
package controller

import (
	"database/sql"
	"encoding/json"
	"net/http"
	"strconv"

	"go-cs/service"
)

type UserController struct {
	userService *service.UserService
}

func NewUserController(userService *service.UserService) *UserController {
	return &UserController{userService: userService}
}

func (c *UserController) GetUser(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.PathValue("id"))
	if err != nil {
		http.Error(w, "Invalid user ID", http.StatusBadRequest)
		return
	}

	user, err := c.userService.GetUser(id)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "User not found", http.StatusNotFound)
			return
		}
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}
```

```service/user_service.go
package service

import (
	"database/sql"

	"go-cs/model"
)

type UserService struct {
	db *sql.DB
}

func NewUserService(db *sql.DB) *UserService {
	return &UserService{db: db}
}

func (s *UserService) GetUser(id int) (*model.User, error) {
	user := &model.User{}
	err := s.db.QueryRow("SELECT id, name, email FROM users WHERE id = ?", id).
		Scan(&user.ID, &user.Name, &user.Email)
	if err != nil {
		return nil, err
	}
	return user, nil
}
```

```main.go
package main

import (
	"database/sql"
	"log"
	"net/http"

	"go-cs/controller"
	"go-cs/service"

	_ "github.com/mattn/go-sqlite3"
)

func main() {
	db, err := sql.Open("sqlite3", "./users.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// テーブル作成
	createTable(db)

	// サンプルデータ挿入
	insertSampleData(db)

	// 依存関係の注入
	userService := service.NewUserService(db)
	userController := controller.NewUserController(userService)

	// ルーティング
	http.HandleFunc("GET /users/{id}", userController.GetUser)

	log.Println("Server starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func createTable(db *sql.DB) {
	query := `
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT NOT NULL UNIQUE
    );`

	_, err := db.Exec(query)
	if err != nil {
		log.Fatal(err)
	}
}

func insertSampleData(db *sql.DB) {
	_, err := db.Exec(`INSERT INTO users (name, email) VALUES (?, ?)`,
		"Tanaka Taro", "taro@example.com")
	if err != nil {
		log.Fatal(err)
	}
}
```

```shell
curl http://localhost:8080/users/1

{"id":1,"name":"Tanaka Taro","email":"taro@example.com"}
```

```shell
curl http://localhost:8080/users/123

User not found
```