Goのフォルダ構成
Goの標準的なフォルダ構成ガイド 📂
Section titled “Goの標準的なフォルダ構成ガイド 📂”Goには厳格なルールはありませんが、プロジェクトのスケーラビリティとメンテナンス性を高めるためのベストプラクティスがコミュニティで共有されています。
1. 主要なディレクトリの役割
Section titled “1. 主要なディレクトリの役割”大規模なプロジェクトでは、以下のディレクトリ構成が一般的です。
cmd/: サーバーやCLIツールなど、実行可能なアプリケーションのエントリーポイントを置きます。各サブディレクトリが独立した実行可能ファイルに対応します。internal/: プロジェクトの内部ロジックを格納します。Goのツールは、このディレクトリ内のコードが外部プロジェクトからインポートされるのを防ぐため、アプリケーションのコアな部分を保護できます。pkg/: 汎用的なヘルパー関数や共通ライブラリなど、他のプロジェクトからも再利用可能な公開コードを置きます。configs/: 環境変数やデータベース接続情報など、アプリケーションの設定ファイルを一元管理します。docs/:API仕様書や設計ドキュメントなど、プロジェクトのドキュメントを格納します。
2. 大規模プロジェクトの構成例
Section titled “2. 大規模プロジェクトの構成例”プロジェクトの目的(APIか、バッチ処理かなど)に応じて、internal内の構造をさらに細かく分けます。
APIサーバーの構成例 🏢
Section titled “APIサーバーの構成例 🏢”APIを主体とするプロジェクトでは、**関心事の分離(Separation of Concerns)**を徹底します。
/my-api-project├── cmd/│ └── api/│ └── main.go # サーバー起動コード├── internal/│ ├── app/ # アプリケーションのコアロジック│ │ ├── handler/ # `HTTP`リクエストのハンドラ│ │ ├── service/ # ビジネスロジック│ │ └── repository/ # データベース操作│ └── middleware/ # 認証やロギングなどの共通処理├── api/│ ├── openapi/│ │ └── openapi.yaml # `OpenAPI`定義│ └── proto/ # `gRPC`の定義ファイル└── go.modバッチ/CLIツールの構成例 💻
Section titled “バッチ/CLIツールの構成例 💻”複数の実行ファイルがある場合、各プログラムの役割を明確にします。
/my-batch-project├── cmd/│ ├── process-data/│ │ └── main.go # データ処理バッチ│ └── worker-cli/│ └── main.go # `CLI`ツール├── internal/│ └── core/│ └── logic.go # 複数の`cmd`で共有されるロジック├── pkg/│ └── job/│ └── job.go # 再利用可能なジョブ処理ライブラリ└── go.mod3. サンプルコード: ミドルウェアの追加 (CORS)
Section titled “3. サンプルコード: ミドルウェアの追加 (CORS)”internal/middleware/cors.goにCORS設定を実装し、cmd/api/main.goでミドルウェアとして利用する例です。
internal/middleware/cors.go:
Section titled “internal/middleware/cors.go:”package middleware
import ( "net/http")
// `CORS`ミドルウェアfunc CORS(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")
// `OPTIONS`リクエスト(プリフライトリクエスト)の場合、200を返して終了 if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return }
// 次のハンドラにリクエストを渡す next.ServeHTTP(w, r) })}cmd/api/main.go:
Section titled “cmd/api/main.go:”package main
import ( "log" "net/http" "my-api-project/internal/app/handler" "my-api-project/internal/middleware")
func main() { // ユーザーハンドラの初期化 userHandler := handler.NewUserHandler()
// ルーターとミドルウェアの設定 router := http.NewServeMux() router.HandleFunc("/users", userHandler.GetUsers)
// `CORS`ミドルウェアを適用 wrappedRouter := middleware.CORS(router)
log.Println("Server is running on :8080") log.Fatal(http.ListenAndServe(":8080", wrappedRouter))}このように、Goのフォルダ構成は、関心事を分離し、コードをモジュール化することで、大規模なシステム開発を効率的に進めるための鍵となります。
4. テンプレート(templates/)ディレクトリの追加
Section titled “4. テンプレート(templates/)ディレクトリの追加”Webアプリケーションを構築する場合、HTMLテンプレートを管理するための専用ディレクトリを設けることが一般的です。これにより、ビジネスロジックとビュー(表示)ロジックが分離され、メンテナンス性が向上します。
追加する場所
Section titled “追加する場所”プロジェクトのルートディレクトリに templates/ を作成します。
/my-web-project├── cmd/│ └── webapp/│ └── main.go├── internal/│ ├── app/│ │ ├── handler/│ │ └── service/│ └── templates/ # `HTML`テンプレートの配置場所│ ├── base.html│ └── index.html├── static/ # `CSS`, `JS`, 画像などの静的ファイル└── go.modハンドラ内でテンプレートをレンダリングする例です。
package handler
import ( "html/template" "net/http")
// `HomePageHandler` はホームページをレンダリングしますfunc HomePageHandler(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles("internal/templates/index.html", "internal/templates/base.html") if err != nil { http.Error(w, "テンプレートの解析に失敗しました", http.StatusInternalServerError) return } tmpl.Execute(w, nil)}5. 環境設定(.env)ファイルの管理
Section titled “5. 環境設定(.env)ファイルの管理”本番環境と開発環境で異なる設定(データベースのURL、APIキーなど)を扱う場合、.envファイルとそれを読み込むロジックを導入することが強く推奨されます。これにより、機密情報をコードベースから分離し、セキュリティを向上させることができます。
追加する場所
Section titled “追加する場所”プロジェクトのルートディレクトリに .env ファイルを作成します。
/my-api-project├── .env # 環境変数の設定ファイル├── cmd/├── internal/└── go.mod準備するもの
Section titled “準備するもの”環境変数を簡単に読み込むために、go-dotenvやviperのようなライブラリを使用すると便利です。
-
インストール:
go get github.com/joho/godotenv -
.envファイルの作成:
DB_URL=postgres://user:password@localhost:5432/mydbAPI_KEY=your-api-key-here- 読み込みコードの追加: アプリケーションのエントリーポイント(
main.go)で.envファイルを読み込みます。
package main
import ( "log" "os" "github.com/joho/godotenv")
func main() { // `.env`ファイルを読み込む err := godotenv.Load() if err != nil { log.Fatalf("Error loading .env file: %v", err) }
// 環境変数を取得 dbURL := os.Getenv("DB_URL") apiKey := os.Getenv("API_KEY")
log.Printf("DB URL: %s, API Key: %s", dbURL, apiKey) // ... 以降のアプリケーションロジック ...}6. ビルドとデプロイのためのスクリプト
Section titled “6. ビルドとデプロイのためのスクリプト”プロジェクトが複雑になるにつれて、ビルド、テスト、デプロイといった一連の作業を手動で行うのは非効率的になります。Makefileやシェルスクリプトを用意することで、これらの作業を自動化・標準化できます。
追加する場所
Section titled “追加する場所”プロジェクトのルートディレクトリに Makefile を作成します。
/my-project├── Makefile # ビルドとデプロイのスクリプト├── cmd/└── go.modMakefileの例
Section titled “Makefileの例”一般的なタスクを定義する例です。
# Makefile.PHONY: build test run
APP_NAME := my-appGO_FILES := $(shell find . -name "*.go")
build: @echo "Building application..." go build -o $(APP_NAME) ./cmd/api
test: @echo "Running tests..." go test ./...
run: build @echo "Starting application..." ./$(APP_NAME)
clean: @echo "Cleaning up..." go clean rm -f $(APP_NAME)このMakefileを使用することで、ターミナルでmake buildと実行するだけでビルドが完了し、make runでアプリケーションを実行できるようになります。
これらの追加要素を考慮することで、より堅牢で管理しやすいGoプロジェクトを構築できます。