golang-project-layout は何をしますか?
Goプロジェクトのレイアウトとワークスペース設定に関するガイドを提供します。新しいGoプロジェクトの開始、既存のコードベースの整理、マルチパッケージのモノレポ構築、複数のmainパッケージを持つCLIツールの作成、cmd/internal/pkgディレクトリ構成の検討、パッケージの再構成や分割について議論する際に使用します。
主なユースケース
- 新しいGoプロジェクトの開始: 標準的なディレクトリ構成を選び、スケーラブルな基盤を構築します。
- 既存コードベースの整理: 命名規則や構造を統一し、メンテナンス性を向上させます。
- モノレポのセットアップ: 複数のパッケージやサービスを単一リポジトリで管理します。
- CLIツールの作成: 複数のエントリポイント(mainパッケージ)を効率的に配置します。
- ディレクトリ構成の選択:
cmd、internal、pkgの適切な使い分けを判断します。 - パッケージ分割の検討: モジュールやパッケージの分割戦略を評価します。
推奨ディレクトリ構成
project-root/
├── cmd/ # アプリケーションのエントリポイント
│ ├── app1/ # 実行可能なmainパッケージ
│ │ └── main.go
│ └── app2/
│ └── main.go
├── internal/ # 非公開パッケージ(外部インポート不可)
│ ├── handler/
│ └── service/
├── pkg/ # 公開パッケージ(外部利用可)
├── api/ # API定義(Protocol Buffers、OpenAPI等)
├── configs/ # 設定ファイル
├── scripts/ # ビルドスクリプト
├── test/ # テストデータやヘルパー
├── go.mod
└── go.sum
ベストプラクティス
-
cmd/ディレクトリ- 各サブディレクトリは独立した
mainパッケージとする。 - ビジネスロジックは
internal/に配置し、cmd/は薄く保つ。
- 各サブディレクトリは独立した
-
internal/ディレクトリ- Goコンパイラにより、外部パッケージからのインポートが制限される。
- プロジェクト内部でのみ利用するコードを格納する。
-
pkg/ディレクトリ- 外部のGoプロジェクトからもインポート可能な公開パッケージを配置する。
- 明確なAPI設計が必要。
-
モノレポ構成
- ワークスペース機能(
go.work)を活用して複数モジュールを管理する。 - 共通ライブラリは
lib/またはpkg/にまとめる。
- ワークスペース機能(
ワークスペース設定例
# go.work
go 1.22
use (
./cmd/app1
./cmd/app2
./pkg/lib
)
CLIツールの構造
複数の main パッケージを持つCLIツールでは、以下のように整理します:
cli-tool/
├── cmd/
│ ├── cli1/
│ │ └── main.go
│ └── cli2/
│ └── main.go
├── internal/
│ ├── commands/
│ ├── config/
│ └── utils/
├── pkg/
│ └── shared/
├── go.mod
└── go.sum
パッケージ分割の判断基準
- 単一責任の原則: パッケージは1つの概念を担当する。
- 循環依存の回避: 依存関係が循環しないよう設計する。
- テスト容易性: 小さなパッケージほどテストが書きやすい。
- 再利用性: 共通機能は
pkg/に分離する。