go-ops について
Go 開発向けのリファレンススキルです。慣用的なコード、並行処理、テスト、プロジェクト構成、性能を扱い、概要とテーマ別資料を提供します。
主な機能
- 01慣用的な Go とエラー処理
- 02並行処理のパターンと指針
- 03インターフェースとジェネリクス
- 04テストとプロジェクト構成
- 05プロファイリングと性能改善
活用シーン
- 01エラー処理方法の選択
- 02Go の並行タスクの設計
- 03Go プロジェクトのパッケージ構成
- 04Go プロジェクトのテストや性能分析
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill go-opsインストール後、Claude Code で/go-opsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/.gitkeepreferences/concurrency.mderror-handling.mdexpert-insights.mdinterfaces-generics.mdperformance.mdproject-structure.mdtesting.mdscripts/.gitkeep詳細
Go の運用
慣用的なパターン、並行処理、本番環境での実践方法を網羅した Go スキルです。
モジュールのクイックスタート
# New module
go mod init github.com/user/project
# Add dependency
go get github.com/lib/pq@latest
# Tidy (remove unused, add missing)
go mod tidy
# Vendor dependencies
go mod vendor
# Workspace (multi-module)
go work init ./api ./shared
go work use ./cli
エラー処理の判断ツリー
What kind of error?
│
├─ Known, expected condition (e.g. "not found")
│ └─ Sentinel error: var ErrNotFound = errors.New("not found")
│ └─ Caller checks: errors.Is(err, ErrNotFound)
│
├─ Need to carry structured data (status code, field name)
│ └─ Custom error type: type ValidationError struct { Field, Message string }
│ └─ Implement Error() string
│ └─ Caller checks: errors.As(err, &validErr)
│
├─ Adding context to an existing error
│ └─ Wrap: fmt.Errorf("load config: %w", err)
│ └─ Preserves original for Is/As checks
│
├─ Truly unrecoverable (corrupted state, programmer bug)
│ └─ panic("invariant violated: ...")
│ └─ Almost never in library code
│
└─ Multiple errors from concurrent work
└─ errors.Join(err1, err2) or multierr package
エラーのラップに関する規約
// Add context at each layer, don't repeat the function name
func LoadUser(id int) (*User, error) {
row, err := db.Query("SELECT ...", id)
if err != nil {
return nil, fmt.Errorf("load user %d: %w", id, err)
}
// ...
}
並行処理の判断ツリー
What's the concurrency pattern?
│
├─ Run N independent tasks, collect results
│ └─ errgroup.Group (cancels on first error)
│
├─ Fire-and-forget background work
│ └─ go func() with context for cancellation
│ └─ ALWAYS handle the error or log it
│
├─ Producer/consumer pipeline
│ └─ Channels (buffered for throughput)
│ └─ Close channel when producer is done
│
├─ Rate-limited concurrent work
│ └─ Semaphore: make(chan struct{}, maxConcurrency)
│
├─ Shared mutable state
│ └─ sync.Mutex or sync.RWMutex
│ └─ Prefer channels if the state is simple
│
├─ One-time initialization
│ └─ sync.Once
│
└─ Wait for N goroutines to finish (no error collection)
└─ sync.WaitGroup
errgroup のクイックスタート
import "golang.org/x/sync/errgroup"
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10) // max 10 concurrent goroutines
for _, url := range urls {
g.Go(func() error {
return fetch(ctx, url)
})
}
if err := g.Wait(); err != nil {
return fmt.Errorf("fetch urls: %w", err)
}
詳しく見る場合:ワーカープール、ファンアウト/ファンイン、パイプラインパターン、context のベストプラクティスについては、./references/concurrency.md を読み込んでください。
インターフェース設計
Accept interfaces, return structs.
// Good: function accepts interface
func Process(r io.Reader) error { ... }
// Good: return concrete type
func NewServer(cfg Config) *Server { ... }
// Bad: returning interface (hides implementation, prevents extension)
func NewServer(cfg Config) ServerInterface { ... }
標準ライブラリでよく使われるインターフェース
| インターフェース | メソッド | 用途 |
|---|---|---|
io.Reader | Read([]byte) (int, error) | あらゆるバイトソース |
io.Writer | Write([]byte) (int, error) | あらゆるバイト出力先 |
io.Closer | Close() error | リソースのクリーンアップ |
fmt.Stringer | String() string | 文字列表現 |
error | Error() string | エラー値 |
sort.Interface | Len, Less, Swap | カスタムソート |
http.Handler | ServeHTTP(w, r) | HTTP ハンドラー |
encoding.BinaryMarshaler | MarshalBinary() ([]byte, error) | バイナリーエンコーディング |
関数オプションパターン
type Option func(*Server)
func WithPort(port int) Option {
return func(s *Server) { s.port = port }
}
func WithTimeout(d time.Duration) Option {
return func(s *Server) { s.timeout = d }
}
func NewServer(opts ...Option) *Server {
s := &Server{port: 8080, timeout: 30 * time.Second} // defaults
for _, opt := range opts {
opt(s)
}
return s
}
// Usage
srv := NewServer(WithPort(9090), WithTimeout(5*time.Second))
詳しく見る場合:ジェネリクス、型制約、埋め込み、型アサーションについては、./references/interfaces-generics.md を読み込んでください。
テストのクイックリファレンス
// Table-driven test
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 1, 2, 3},
{"zero", 0, 0, 0},
{"negative", -1, -2, -3},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.expected {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.expected)
}
})
}
}
# Run tests
go test ./...
# With coverage
go test -cover -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run specific test
go test -run TestAdd ./pkg/math/
# Benchmarks
go test -bench=. -benchmem ./...
# Race detector
go test -race ./...
# Fuzz testing
go test -fuzz=FuzzParse ./...
詳しく見る場合:インターフェースを使ったモック、httptest、testcontainers、ゴールデンファイルについては、./references/testing.md を読み込んでください。
よくある落とし穴
| 落とし穴 | 理由 | 対処法 |
|---|---|---|
| nil スライスと空スライス | var s []int は nil、s := []int{} は空です。json.Marshal の結果はそれぞれ null と [] になります | JSON が重要な場合は make([]int, 0) または []int{} を使います |
| ゴルーチンリーク | 読み手/書き手がいないチャネルでゴルーチンがブロックされます | context.WithCancel を使い、必ず終了経路を用意します |
| ループ内の defer | 遅延呼び出しは関数が戻るまで実行されません | ループ本体をクロージャーで囲むか、明示的にクリーンアップします |
| インターフェースの nil に関する落とし穴 | (*MyType)(nil) を error インターフェースに代入すると、== nil になりません | nil の型付きポインターではなく、明示的に nil を返します |
| range 変数のキャプチャ | ループ変数は再利用されます(Go 1.22 より前) | go func(v T) { ... }(v) を使うか、Go 1.22 以降にアップグレードします |
| ループ内での文字列連結 | O(n^2) のメモリー割り当てが発生します | strings.Builder を使います |
sync.WaitGroup での Go 実行後の Add | 競合状態が発生します | go func() の前に wg.Add(1) を呼び出します |
| バッファーなしチャネルのデッドロック | 送信と受信を同時に行う必要があります | バッファー付きチャネルまたは別々のゴルーチンを使います |
map は並行利用に安全ではありません | 競合状態が発生し、クラッシュする可能性があります | sync.Mutex または sync.Map を使います |
プロジェクト構成
project/
├── cmd/
│ ├── api/main.go # Entry points
│ └── worker/main.go
├── internal/ # Private packages
│ ├── handler/
│ ├── service/
│ └── repository/
├── pkg/ # Public packages (optional)
├── go.mod
├── go.sum
├── Makefile # or justfile
└── .golangci.yml
詳しく見る場合:ワークスペースモード、ビルドタグ、ldflags、リンター設定については、./references/project-structure.md を読み込んでください。
パフォーマンスのクイックリファレンス
# CPU profile
go test -cpuprofile=cpu.prof -bench=. ./...
go tool pprof cpu.prof
# Memory profile
go test -memprofile=mem.prof -bench=. ./...
go tool pprof -alloc_space mem.prof
# Trace
go test -trace=trace.out ./...
go tool trace trace.out
# Escape analysis
go build -gcflags='-m' ./...
| 最適化 | 適用場面 | パターン |
|---|---|---|
| スライスの事前割り当て | サイズが既知の場合 | make([]T, 0, n) |
strings.Builder | 文字列連結 | var b strings.Builder |
sync.Pool | 同じ型の頻繁な割り当て/解放 | pool.Get() / pool.Put() |
| 構造体フィールドのアラインメント | メモリーが重要な場合 | サイズの大きい順にフィールドをまとめます |
| バッファーの再利用 | I/O が多い場合 | bufio.NewReaderSize(r, 64*1024) |
詳しく見る場合:pprof の手順、ベンチマークパターン、エスケープ解析については、./references/performance.md を読み込んでください。
リファレンスファイル
詳しく知りたいトピックについては、以下を読み込んでください。各ファイルは単独で参照できます。
| リファレンス | 読み込むタイミング |
|---|---|
./references/concurrency.md | Goroutine、チャネル、コンテキスト、同期プリミティブ、ワーカープール、パイプライン |
./references/error-handling.md | エラーのラップ、センチネルエラー、カスタム型、複数のエラー、panic/recover |
./references/testing.md | テーブル駆動テスト、モック、httptest、ベンチマーク、ファジング、testcontainers、ゴールデンファイル |
./references/interfaces-generics.md | インターフェース設計、埋め込み、型アサーション、ジェネリクス、型制約 |
./references/project-structure.md | 標準レイアウト、go.mod、ワークスペース、ビルドタグ、ldflags、golangci-lint |
./references/performance.md | pprof、trace、ベンチマーク、エスケープ解析、sync.Pool、構造体のアラインメント |
./references/expert-insights.md | HTTP サーバー(Go 1.22 のルーティング)、グレースフルシャットダウン、http.Client のチューニング、JSON ヘルパー |
関連項目
docker-ops- Go バイナリのマルチステージビルド(scratch/distroless)ci-cd-ops- Go の CI パイプライン、Go モジュールのキャッシュ、goreleasertesting-ops- 言語をまたいだテスト戦略
コメント
Markdown 対応