0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go】フォルダ構成のリファクタリングとweb frameworkの比較

Posted at

はじめまして!フリーランスエンジニアのこたろうです。
アプリケーションのフォルダ構成の改善とWebフレームワークの比較について、学びで得た知見を共有します。

フォルダ構成の改善

1. なぜCORS設定とルーティングを分離するのか?

プログラムを書く際、1つのファイルに多くの処理を書くと、以下の問題が発生します:

  • コードが読みにくくなる
  • 修正が難しくなる
  • 他の人が理解しにくい

そこで、CORS設定とルーティングを別ファイルに分けることで:

  • 各ファイルの役割が明確になる
  • コードが整理され、読みやすくなる
  • 修正が容易になる

CORS設定の分離例

// config/cors.go

// CORSとは?
// Cross-Origin Resource Sharing(CORS)は、
// 異なるドメインからのアクセスを制御する仕組みです。
// 例:localhost:3000のフロントエンドから
//     localhost:8080のバックエンドにアクセスする場合に必要

func CorsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // どのドメインからのアクセスを許可するか
        w.Header().Set("Access-Control-Allow-Origin", "*")
        
        // どのHTTPメソッドを許可するか
        w.Header().Set("Access-Control-Allow-Methods", 
            "GET, POST, PUT, DELETE, OPTIONS")
        
        // どのヘッダーを許可するか
        w.Header().Set("Access-Control-Allow-Headers", 
            "Content-Type, Authorization")
        
        // プリフライトリクエストの処理
        if r.Method == "OPTIONS" {
            w.WriteHeader(http.StatusOK)
            return
        }
        
        next.ServeHTTP(w, r)
    })
}

ルーティングの分離例

// config/router.go

// ルーティングとは?
// URLと処理(関数)を紐付けることです
// 例:/api/todosにアクセスしたら、GetTodos関数を実行する

func NewRouter() *mux.Router {
    router := mux.NewRouter()
    
    // GETメソッド:データの取得
    router.HandleFunc("/api/todos", controllers.GetTodos).
        Methods("GET")
    
    // POSTメソッド:データの作成
    router.HandleFunc("/api/todos", controllers.CreateTodo).
        Methods("POST")
    
    // PUTメソッド:データの更新
    router.HandleFunc("/api/todos/{id}", controllers.UpdateTodo).
        Methods("PUT")
    
    // DELETEメソッド:データの削除
    router.HandleFunc("/api/todos/{id}", controllers.DeleteTodo).
        Methods("DELETE")
    
    return router
}

2. レイヤードアーキテクチャとは?

アプリケーションを以下の3つの層に分けて管理する方法です:

  1. Controllers層(入口)

    • ユーザーからのリクエストを受け取る
    • データの形式をチェック
    • Services層に処理を依頼
    • 結果をユーザーに返す
  2. Services層(ビジネスロジック)

    • アプリケーションの主要な処理を行う
    • データの加工や計算
    • 複雑なチェック処理
    • Repositories層にデータの操作を依頼
  3. Repositories層(データ操作)

    • データベースとのやり取り
    • データの保存、取得、更新、削除

フォルダ構成例

├── controllers/
│   └── todo_controller.go  (リクエストの受付)
├── services/
│   └── todo_service.go     (ビジネスロジック)
└── repositories/
    └── todo_repository.go  (データベース操作)

実装例と説明

// repositories/todo_repository.go
// データベース操作を担当
type TodoRepository interface {
    FindAll() ([]Todo, error)      // 全データ取得
    FindByID(id int) (*Todo, error) // 1件取得
    Create(todo *Todo) error       // データ作成
    Update(todo *Todo) error       // データ更新
    Delete(id int) error           // データ削除
}

// services/todo_service.go
// ビジネスロジックを担当
type TodoService struct {
    repo TodoRepository  // repositoryを使用
}

func (s *TodoService) GetTodos() ([]Todo, error) {
    // 1. repositoryからデータを取得
    todos, err := s.repo.FindAll()
    if err != nil {
        return nil, err
    }
    
    // 2. 必要な加工や計算を行う
    // (例:期限切れのTODOに印をつけるなど)
    for i := range todos {
        if todos[i].DueDate.Before(time.Now()) {
            todos[i].IsExpired = true
        }
    }
    
    return todos, nil
}

// controllers/todo_controller.go
// リクエストの受付を担当
type TodoController struct {
    service *TodoService  // serviceを使用
}

func (c *TodoController) GetTodos(w http.ResponseWriter, r *http.Request) {
    // 1. リクエストのチェック
    // (必要に応じてバリデーションなど)
    
    // 2. serviceに処理を依頼
    todos, err := c.service.GetTodos()
    if err != nil {
        // エラー時の処理
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    // 3. 結果をJSONで返す
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(todos)
}

このように分けることで:

  • コードが整理され、理解しやすくなる
  • テストが書きやすくなる
  • 修正が容易になる
  • チーム開発がスムーズになる

gorilla/muxとginの比較

gorilla/mux

標準パッケージnet/httpを拡張したシンプルなフレームワーク

メリット

  1. 学習が簡単

    • 標準パッケージの知識がそのまま使える
    • シンプルな機能で分かりやすい
  2. 柔軟なルーティング

    • URLに変数を含められる
    • HTTPメソッドで分岐できる
// gorilla/muxの例
r := mux.NewRouter()

// URLに変数を含む例(/api/todos/1 など)
r.HandleFunc("/api/todos/{id}", getTodo).Methods("GET")

// 複数のHTTPメソッドを設定
r.HandleFunc("/api/todos", handler).
    Methods("GET", "POST")

gin

高機能で高速なWebフレームワーク

メリット

  1. 便利な機能が豊富

    • バリデーション(データチェック)
    • ミドルウェア(共通処理)
    • エラーハンドリング
  2. 高いパフォーマンス

    • 処理が速い
    • メモリ使用量が少ない
// ginの例
r := gin.Default()

// シンプルなルーティング
r.GET("/api/todos/:id", getTodo)

// バリデーション機能の例
type Todo struct {
    Title string `binding:"required,min=1,max=100"`
    Done  bool
}

どちらを選ぶべき?

  1. 小規模なプロジェクト
    → gorilla/mux

    • シンプルで学習コストが低い
    • 標準パッケージの勉強になる
  2. 大規模なプロジェクト
    → gin

    • 便利な機能が揃っている
    • パフォーマンスが重要な場合

参考文献:
-『Goで作るはじめてのWebアプリケーション改訂版』技術評論社

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?