Go Mastery Skill(Goマスタリースキル)
あらゆる目的のために、プロダクション品質で慣用的なGoコードを記述します。このスキルは、Go 1.22+(2024~2026年)時点のGoエコシステムの集合知をエンコードしています。
Goバージョンベースライン: 1.22 | 対象機能: 1.26まで | 最終更新: 2026年2月
Goコードを書く前に、以下の原則を内部化してください。特定のトピックの詳細については、参照ファイルを読んでください。
参照ファイル — 必要に応じて読む
| ファイル | 読むタイミング |
|---|---|
references/concurrency.md | ゴルーチン、チャネル、同期プリミティブ、並列処理 |
references/http-and-apis.md | HTTPサーバー、ルーター、ミドルウェア、REST/gRPC API、WebSocket |
references/database.md | SQL、ORM、コネクションプール、マイグレーション、トランザクション |
references/testing.md | ユニットテスト、結合テスト、ベンチマーク、ファジング |
references/errors-and-resilience.md | エラーハンドリング、リトライ、サーキットブレーカー、グレースフルデグラデーション |
references/performance.md | プロファイリング、アロケーション削減、GCチューニング、ベンチマーク |
references/cli-and-config.md | CLIフレームワーク、設定、環境管理 |
references/project-patterns.md | プロジェクト構成、DI、プラグインシステム、コード生成 |
references/platform-and-build.md | クロスコンパイル、Windows固有の設定、埋め込み、配布 |
references/security.md | 認証、シークレット、入力バリデーション、TLS、OWASPパターン |
references/modern-go.md | Go 1.21~1.26の機能、非推奨パターン、事前トレーニングが誤ること |
references/advanced-patterns.md | ジェネリクス、ステートマシン、ストリーミング、スケジューリング、AI/LLM統合 |
references/advanced-resources.md | 厳選された外部リソース: コンパイラ/ランタイム内部、アセンブリ、unsafe、cgo、Raft、K8sオペレーター、Wasm、暗号、プロファイリング、書籍、カンファレンス、学術論文 |
references/observability.md | OpenTelemetryセットアップ、トレーシング、メトリクス、トレース相関のある構造化ログ、ヘルスチェック、フライトレコーダー、プロダクションインストルメンテーションチェックリスト |
references/ecosystem-and-tooling.md | キュレーションリスト(awesome-go)、フレームワーク比較(Web、ORM、CLI、DI、設定)、スタイルガイド、CI/CD、Docker、リリース管理、脆弱性スキャン、学習プラットフォーム、Goガバナンス |
references/internals.md | GMPスケジューラー、ガベージコレクター、メモリモデル、スタック管理、メモリアロケーター、コンパイラパイプライン、unsafe、リフレクション、コンパイラディレクティブ |
references/networking.md | TCP/UDPサーバー、net.Conn期限、コネクションプーリング、mTLS、Unixソケット、DNSリゾルバー、カスタムバイナリプロトコル、gnet |
references/mcp-and-agents.md | MCPサーバー(mcp-go、公式SDK)、ツール/リソース/プロンプト、エージェントフレームワーク(ADK、langchaingo、eino)、マルチエージェントパターン、gopls MCP |
references/api-design.md | REST命名、ページネーション(カーソル/オフセット)、RFC 9457エラー、レート制限、APIバージョニング、OpenAPIコード生成(oapi-codegen)、後方互換性、非推奨ヘッダー |
references/cgo-and-interop.md | CGoの基本、C型マッピング、境界を越えたメモリ管理、ポインタ受け渡しルール、コールバック、静的/動的リンク、クロスコンパイル、Pure Goの代替 |
references/design-patterns.md | GoにおけるGoFパターン(Factory、Builder、Strategy、Observer、Decorator)、継承よりコンポジション、決定木 |
references/distributed-systems.md | Raft、Outboxパターン、サーガ、分散ロック、冪等性、CRDT、コンシステントハッシュ |
references/cloud-native.md | Kubernetes client-go、controller-runtimeオペレーター、Admission Webhook、リーダー選出、Helm/Kustomize |
references/debugging-and-diagnostics.md | Delveデバッガー、スタックトレース、GODEBUGフラグ、プロファイリングワークフロー、症状から診断へのテーブル |
references/style-synthesis.md | Google + Uber + コミュニティのスタイルルールを統合、命名、フォーマット、コード構成 |
references/modules-and-dependencies.md | go.mod操作、MVS、ワークスペース、GOPROXY、GOAUTH、ベンダリング、マルチモジュールモノレポ |
references/encoding-and-serialization.md | JSON(v1/v2)、Protocol Buffers、MessagePack、CBOR、CSV、YAML、TOML、フォーマット決定テーブル |
references/wasm-and-embedded.md | WebAssembly(WASI、ブラウザ)、go:wasmexport、TinyGo、組み込み/IoTパターン |
references/migration-guides.md | Python、Java、TypeScript、Rust、C++からの慣用的なGo翻訳 — 概念マップと落とし穴 |
references/testing-advanced.md | プロパティベーステスト(rapid)、コントラクトテスト(Pact)、負荷テスト(Vegeta)、カオスエンジニアリング、synctest高度 |
references/supply-chain-security.md | govulncheck、SBOM生成、SLSAフレームワーク、cosign、再現可能ビルド、GODEBUG互換性 |
references/ebpf.md | GoからのeBPF(cilium/ebpf)、bpf2goワークフロー、トレーシング、ネットワーキング、カーネルレベルのプロファイリング |
references/event-driven.md | Kafka、RabbitMQ、NATSコンシューマー/プロデューサー、Watermillフレームワーク、DLQ、Exactly-onceパターン |
references/data-structures-and-caching.md | container/heap、container/list、LRUキャッシュ、singleflight、シャーディングされたマップ、ブルームフィルター、ウィークリファレンスキャッシュ、キャッシュ戦略パターン(aside/write-through/write-behind) |
references/ai-ml-beyond-llm.md | ONNX Runtime推論、Gonum、ベクターDBクライアント、埋め込みパイプライン、GoからのMLサーブ |
references/file-io.md | ファイル操作、io.Reader/Writer構成、バッファリングI/O、ストリーミング、パス処理、os.Root、fs.FS抽象化、fsnotify |
核となる哲学
Goは意図的にシンプルです。他のエコシステムから複雑さをインポートしたくなる衝動を抑えてください。
- 明確さは巧妙さに勝る。 コードは書かれるよりも10倍多く読まれます。暗黙的より明示的 — 将来のメンテナー(将来の自分も含む)が感謝するでしょう。
- 継承よりコンポジション。 インターフェースと構造体を埋め込み、深い階層を避けてください。Goにクラスはなく、それは意図的です — 小さな組み合わせ可能な部品が複雑な型ツリーに勝ります。
- インターフェースを受け入れ、構造体を返す。 関数は振る舞い(インターフェース)に依存し、具象型を公開する必要があります。これにより、呼び出し元は柔軟性を保ちながら、実装の発見可能性とデバッグ可能性を維持できます。
- ゼロ値を有用にせよ。
var x Tが初期化なしで使用可能になるように型を設計してください。これにより、nilポインタバグのクラス全体が排除され、APIが自然に感じられるようになります(bytes.Buffer、sync.Mutex、http.Clientはすべてゼロ値で動作します)。 - エラーは値である。 それらを処理してください。決して無視しないでください。
fmt.Errorf("doing X: %w", err)を使用してコンテキストでラップしてください。破棄されたエラーは、数時間後に本番環境で顕在化する静かな障害になります。 - 停止できないゴルーチンを開始しないでください。 すべてのゴルーチンには、コンテキストのキャンセルまたはチャネルのクローズによるシャットダウンパスが必要です。リークしたゴルーチンはメモリを無期限に消費し、グレースフルシャットダウンを不可能にします。
- まず標準ライブラリ。 Goの標準ライブラリは異常に充実しています。標準ライブラリが本当に不足している場合にのみサードパーティライブラリに手を伸ばしてください — 依存関係が少ないほど、セキュリティ監査、バージョン競合、ビルド時間が削減されます。
- コードは
gofmtでクリーンになり、ビルドされ、vetされるまで完成ではありません。gofmt/goimports、go build、go vet、go test -race、golangci-lintを実行してください — それらをCIゲートにしてください;レースデテクターはレビューでは見えないバグを見つけます。ツールにアクセスせずにコードを生成する場合も、同じ基準を手動で維持してください:gofmt形式を維持し、実際に使用するインポートのみを含めてください(未使用のインポートはコンパイルエラーです — ある慣用句を別の慣用句に置き換えた直後の古典的なミス)。 - 呼び出し元の契約を尊重し、その後に最適化せよ。 タスクが正確な識別子、シグネチャ、出力形式、または型を指定している場合、それらを正確に再現してください — たとえあなたなら別の名前や構造にしたい場合でも。仕様を満たす最も単純で正しい解決策をデフォルトとし、タスクの複雑さがそれを要求する場合にのみ、抽象化、間接化、または防御的レイヤーを追加してください。要求された表面に一致すること自体が正しさの一部です — 不必要な名前変更や再構築は呼び出し元とテストを壊します。
プロジェクト構造
シンプルに始めてください。プロジェクトが要求する場合にのみ構造を追加してください。
単一バイナリ(CLIまたは小規模サービス)
myapp/
├── go.mod
├── main.go # package main、エントリーポイント
├── app.go # コアアプリケーションロジック
├── app_test.go
└── internal/ # 必要に応じてプライベートパッケージ
└── parser/
├── parser.go
└── parser_test.go
マルチバイナリ/プロダクションサービス
myproject/
├── go.mod
├── cmd/ # エントリーポイント — 薄いmain()関数
│ ├── api-server/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # プライベートアプリケーションコード(コンパイラによって強制)
│ ├── auth/
│ ├── user/ # ドメインパッケージ: handler + service + repo
│ │ ├── handler.go
│ │ ├── service.go
│ │ ├── repository.go
│ │ └── model.go
│ ├── platform/ # 横断的: db、cache、logging
│ │ ├── postgres/
│ │ └── redis/
│ └── middleware/
├── pkg/ # オプション: 公開再利用可能ライブラリ
├── api/ # OpenAPI仕様、protobuf定義
├── migrations/ # SQLマイグレーションファイル
├── scripts/ # ビルド、デプロイ、開発ツール
├── configs/ # デフォルト設定ファイル
└── Makefile
主要なルール:
internal/はGoコンパイラによって強制されます — ここにあるコードは外部モジュールからインポートできません。cmd/*/main.goは薄くあるべきです:フラグを解析し、依存関係をワイヤリングし、run()を呼び出し、シャットダウンを処理します。- 技術レイヤーではなく、ドメイン/機能でグループ化してください。
models/、controllers/、services/は避けてください — これらはGoのパッケージモデルと戦うJavaスタイルのレイヤリングです。 utils/、helpers/、common/パッケージは避けてください — パッケージは提供するものにちなんで命名してください。あいまいな名前は無関係なコードを引き寄せ、インポートを無意味にします。- ディレクトリはパッケージです。単に整理のためにディレクトリを作成しないでください。
命名規則
// パッケージ: 短く、小文字、単一単語。アンダースコアやmixedCapsは使用しない。
package user // 良い
package userService // 悪い — mixedCaps
// エクスポート: MixedCaps。非エクスポート: mixedCaps。アンダースコアは合法ですが、
// コミュニティはスタイルバグとして扱います — 非慣用的なコードを示します。
func ParseRequest() // エクスポート
func parseHeader() // 非エクスポート
// インターフェース: 単一メソッドインターフェースにはメソッド + "-er" 接尾辞
type Reader interface { Read(p []byte) (n int, err error) }
type Validator interface { Validate() error }
// ゲッター: Owner()、GetOwner()ではない。セッター: SetOwner()。
func (u *User) Name() string // ゲッター — 「Get」プレフィックスはGoらしくない
func (u *User) SetName(n string) // セッター
// 頭字語: すべて大文字。URL、HTTP、ID、API — Url、Http、Id、Apiではない。
type HTTPClient struct{}
var userID int
// エラー変数: ErrXxx。エラー型: XxxError。
var ErrNotFound = errors.New("not found")
type ValidationError struct { Field string; Message string }
// コンテキスト: 最初のパラメーター、常にctxという名前。これは普遍的なGoの慣例であり、
// どのコードベースでもコンテキストの伝播を即座に認識可能にします。
func (s *Service) GetUser(ctx context.Context, id string) (*User, error)
エラーハンドリング
これはGoの最も特徴的なパターンです。習得してください。
// すべてのエラーをチェック — %wでコンテキストをラップ
f, err := os.Open(name)
if err != nil {
return fmt.Errorf("opening config %s: %w", name, err)
}
defer f.Close()
// errors.AsType — ジェネリック型付きエラー抽出 [Go 1.26+]
// errors.Asよりも推奨: 型安全、事前宣言変数不要。
if pathErr, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("failed at path:", pathErr.Path)
}
主要なルール:
return errのままコンテキストがないとデバッグが苦痛になります — 常にfmt.Errorf("doing X: %w", err)でラップしてください。- ライブラリコードでの
log.Fatal(err)はos.Exit(1)を呼び出し、deferによるクリーンアップをスキップします — エラーを呼び出し元に返してください。 panic()はプログラマのバグ用であり、ランタイム状態用ではありません — 代わりにエラーを返してください。- サードパーティのエラーは
%v(%wではない)でラップして、呼び出し元を基礎となるエラー型に結合しないようにしてください。 - エラーメッセージスタイル: 小文字、句読点なし:
fmt.Errorf("reading config file: %w", err)。
詳細については、references/errors-and-resilience.md を参照してください。センチネルエラー、カスタムエラー型、errors.Join、リトライパターン、サーキットブレーカー、グレースフルデグラデーションについて説明しています。
並行性の基本
包括的なパターン(errgroup、ワーカープール、ファンアウト/ファンインを含む)については、references/concurrency.md を参照してください。核となるルール:
- キャンセルにはコンテキストを使用する。 すべてのゴルーチンは
ctx.Done()をチェックする必要があります — これがないと、「作業を停止」を通知する方法がありません。 - 生の
sync.WaitGroupよりもerrgroupを優先する。 待機 + エラー収集 + コンテキストキャンセルをバンドルします。SetLimitを使用した完全な例についてはconcurrency.mdを参照してください。 - 共有状態を保護する — 通信にはチャネル、より単純な場合はミューテックス。各ミューテックスが何を保護するかをコメントしてください。
- すべてのゴルーチンにはシャットダウンパスが必要です。 キャンセルチェックがない = リークしたゴルーチン = メモリリーク。
- ゴルーチン内のパニックはプロセス全体を強制終了します。 生成されたゴルーチンで回復するか、
sourcegraph/concを使用してください。
新しい同期プリミティブ:
sync.OnceValue / sync.OnceValues [Go 1.21+] — sync.Once + パッケージ変数を置き換える型安全な遅延初期化:
var loadConfig = sync.OnceValues(func() ([]byte, error) {
return os.ReadFile("config.json") // 正確に1回実行され、どのゴルーチンからも安全
})
data, err := loadConfig() // 後続の呼び出しはキャッシュされた結果を返す
sync.WaitGroup.Go [Go 1.25+] — Add(1) + go func + Done() を組み合わせる:
var wg sync.WaitGroup
wg.Go(func() { process(1) })
wg.Go(func() { process(2) })
wg.Wait()
チャネルサイジング: 同期には非バッファ(0)、シグナルにはバッファ(1)、既知の境界のある作業にはバッファ(N)。
インターフェース
// インターフェースを受け入れ、具象型を返す
type UserStore interface {
GetUser(ctx context.Context, id string) (*User, error)
}
func NewService(store UserStore) *Service { return &Service{store: store} }
// インターフェースは小さく保つ — 1~3メソッド。小さなインターフェースから大きなものを構成する。
type ReadWriter interface { Reader; Writer }
// インターフェースを定義する場所: 消費者側、プロデューサー側ではない。
// 必要な動作を宣言するだけで、使用するパッケージがそれに応じて適合する。
type Server struct{}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {} // 自由にインターフェースを実装
// テスト用のインターフェースモック: 標準ライブラリのインターフェースをラップした単純な実装から始める。
// 複雑なモッキングライブラリは避ける。
type StubUserStore struct {
users map[string]*User
}