golang-pro について
golang-proは、バックエンドサービス、コマンドラインツール、分散システムを開発するGo開発者向けのスキルです。Go 1.21以降、並行処理、性能改善、標準ライブラリの慣用的な使い方を扱います。
主な機能
- 01Go 1.21以降の言語ガイド
- 02goroutineとchannelの並行処理パターン
- 03バックエンドとネットワークサービスのパターン
- 04性能分析と最適化
- 05エラー処理とテストの実践
活用シーン
- 01並行処理を用いたGoサービスの構築
- 02コマンドラインツールの開発
- 03Goアプリケーションの性能改善
- 04分散システムのコンポーネント設計
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ 404kidwiz/ claude-supercode-skills --skill golang-proインストール後、Claude Code で/golang-proを入力して読み込まれたか確認します。
詳細
Go Pro Specialist
目的
Go 1.21 以降の機能、goroutine とチャネルを使った並行システム、高性能なバックエンドサービスを専門とする、Go プログラミングのエキスパート向け機能を提供します。Go の慣用的なパターンと標準ライブラリを幅広く活用して、スケーラブルなマイクロサービス、CLI ツール、分散システムを構築することを得意としています。
使用する場面
- Go で高性能なマイクロサービス(HTTP サーバー、gRPC、API ゲートウェイ)を構築する
- goroutine とチャネルを使った並行システム(ワーカープール、パイプライン)を実装する
- cobra または標準ライブラリを使って CLI ツール(システムユーティリティ、DevOps ツール)を開発する
- ネットワークサービス(TCP/UDP サーバー、WebSocket サーバー、プロキシ)を作成する
- 並行ストリーム処理を使ったデータ処理パイプラインを構築する
- Go アプリケーションのパフォーマンスを最適化する(pprof によるプロファイリング、割り当ての削減)
- 分散システムのパターン(サービスディスカバリー、サーキットブレーカー)を実装する
- Go 1.21 以降のジェネリクスと型パラメーターを扱う
Go 1.21 以降の機能、goroutine とチャネルを使った並行プログラミング、標準ライブラリの幅広い活用を専門とするエキスパート Go 開発者で、高性能な並行システムの構築を支援します。
2. 判断フレームワーク
並行処理パターンの選択
Use Case Analysis
│
├─ Need to process multiple items independently?
│ └─ Worker Pool Pattern ✓
│ - Buffered channel for jobs
│ - Fixed number of goroutines
│ - WaitGroup for completion
│
├─ Need to transform data through multiple stages?
│ └─ Pipeline Pattern ✓
│ - Chain of channels
│ - Each stage processes and passes forward
│ - Fan-out for parallel processing
│
├─ Need to merge results from multiple sources?
│ └─ Fan-In Pattern ✓
│ - Multiple input channels
│ - Single output channel
│ - select statement for multiplexing
│
├─ Need request-scoped cancellation?
│ └─ Context Pattern ✓
│ - context.WithCancel()
│ - context.WithTimeout()
│ - Propagate through call chain
│
├─ Need to synchronize access to shared state?
│ ├─ Read-heavy workload → sync.RWMutex
│ ├─ Simple counter → sync/atomic
│ └─ Complex coordination → Channels
│
└─ Need to ensure single initialization?
└─ sync.Once ✓
エラー処理戦略マトリクス
| シナリオ | パターン | 例 |
|---|---|---|
| コンテキスト情報を付けてエラーをラップする | fmt.Errorf("%w") | return fmt.Errorf("failed to connect: %w", err) |
| カスタムエラー型 | Error() を持つ構造体を定義する | type ValidationError struct { Field string } |
| センチネルエラー | var ErrNotFound = errors.New("not found") | if errors.Is(err, ErrNotFound) { ... } |
| エラー型を確認する | errors.As() | var valErr *ValidationError; if errors.As(err, &valErr) { ... } |
| 複数の戻り値でエラーを返す | 値とエラーの両方を返す | func Get(id string) (*User, error) |
| プログラマーエラーの場合のみ panic を使う | panic("unreachable code") | 想定される失敗では panic を使わない |
HTTP フレームワークの判断ツリー
HTTP Server Requirements
│
├─ Need full-featured framework with middleware?
│ └─ Gin or Echo ✓
│ - Routing, middleware, validation
│ - JSON binding
│ - Production-ready
│
├─ Need microframework for simple APIs?
│ └─ Chi or Gorilla Mux ✓
│ - Lightweight routing
│ - stdlib-compatible
│ - Fine-grained control
│
├─ Need maximum performance and control?
│ └─ net/http stdlib ✓
│ - No external dependencies
│ - Full customization
│ - Good for learning
│
└─ Need gRPC services?
└─ google.golang.org/grpc ✓
- Protocol Buffers
- Streaming support
- Cross-language
注意すべき兆候 → Oracle にエスカレーション
| 観察事項 | エスカレーションする理由 | 例 |
|---|---|---|
| goroutine リークによるメモリ増加 | 複雑なライフサイクル管理 | 「メモリが際限なく増加する。goroutine が終了していない可能性がある」 |
| mutex を使っているのに発生する競合状態 | 微妙な同期バグ | 「go test -race により、本番コードでデータ競合が検出される」 |
| コンテキストのキャンセルが伝播しない | 分散システムの調整 | 「クライアント切断後も、キャンセルされたリクエストが実行され続ける」 |
| ジェネリクスによりコンパイル時間が大幅に増加する | 型システムの複雑さ | 「制約付きジェネリック関数のコンパイルに 10 分以上かかる」 |
| CGO によるメモリ破損 | unsafe コードとの相互作用 | 「Go から C ライブラリを呼び出すとセグフォルトが発生する」 |
ワークフロー 2:グレースフルシャットダウンに対応した HTTP サーバー
シナリオ:ミドルウェアとグレースフルシャットダウンを備えた、本番環境対応の HTTP サーバー
ステップ 1:サーバー構造体を定義する
package main
import (
"context"
"errors"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
type Server struct {
httpServer *http.Server
logger *log.Logger
}
func NewServer(addr string, handler http.Handler) *Server {
return &Server{
httpServer: &http.Server{
Addr: addr,
Handler: handler,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second,
},
logger: log.New(os.Stdout, "[SERVER] ", log.LstdFlags|log.Lmicroseconds),
}
}
func (s *Server) Start() error {
s.logger.Printf("Starting server on %s", s.httpServer.Addr)
if err := s.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
return err
}
return nil
}
func (s *Server) Shutdown(ctx context.Context) error {
s.logger.Println("Shutting down server...")
return s.httpServer.Shutdown(ctx)
}
ステップ 2:ミドルウェアを実装する
// Middleware for logging
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Wrap response writer to capture status code
wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(wrapped, r)
log.Printf("%s %s %d %s", r.Method, r.URL.Path, wrapped.statusCode, time.Since(start))
})
}
type responseWriter struct {
http.ResponseWriter
statusCode int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
// Middleware for panic recovery
func RecoveryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("Panic recovered: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
// Middleware for request timeout
func TimeoutMiddleware(timeout time.Duration) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), timeout)
defer cancel()
r = r.WithContext(ctx)
done := make(chan struct{})
go func() {
next.ServeHTTP(w, r)
close(done)
}()
select {
case <-done:
return
case <-ctx.Done():
http.Error(w, "Request Timeout", http.StatusRequestTimeout)
}
})
}
}
ステップ 3:ルートとグレースフルシャットダウンを設定する
func main() {
// Setup routes
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
// Simulate slow endpoint
time.Sleep(2 * time.Second)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"users": []}`))
})
// Apply middleware chain
handler := RecoveryMiddleware(LoggingMiddleware(TimeoutMiddleware(5 * time.Second)(mux)))
// Create server
server := NewServer(":8080", handler)
// Start server in goroutine
go func() {
if err := server.Start(); err != nil {
log.Fatalf("Server failed: %v", err)
}
}()
// Wait for interrupt signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
// Graceful shutdown with 30s timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Printf("Server shutdown error: %v", err)
}
log.Println("Server stopped")
}
期待される結果:
- タイムアウトを備えた本番環境対応の HTTP サーバー
- ミドルウェアチェーン(ロギング、リカバリー、タイムアウト)
- グレースフルシャットダウン(処理中のリクエストを完了する)
- goroutine リークやリソースリークがない
4. パターンとテンプレート
パターン 1:キャンセルのためのコンテキスト伝播
ユースケース:クライアント切断時に、すべての下流処理をキャンセルする
// Template: Context-aware HTTP handler
func HandleRequest(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Pass context to all downstream calls
result, err := fetchData(ctx)
if err != nil {
if errors.Is(err, context.Canceled) {
// Client disconnected
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(result)
}
func fetchData(ctx context.Context) (*Data, error) {
// Check context before expensive operation
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
// Simulate database call with timeout
resultChan := make(chan *Data, 1)
errChan := make(chan error, 1)
go func() {
// Actual database query
time.Sleep(2 * time.Second)
resultChan <- &Data{Value: "result"}
}()
select {
case result := <-resultChan:
return result, nil
case err := <-errChan:
return nil, err
case <-ctx.Done():
return nil, ctx.Err() // Canceled or timed out
}
}
パターン 3:テーブル駆動テスト
ユースケース:最小限のコードで包括的なテストカバレッジを実現する
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -2, -3, -5},
{"mixed signs", -2, 3, 1},
{"zero values", 0, 0, 0},
{"large numbers", 1000000, 2000000, 3000000},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
}
})
}
}
❌ アンチパターン:Range ループ変数のキャプチャ
具体例:
// WRONG: All goroutines reference same variable
for _, user := range users {
go func() {
fmt.Println(user.Name) // Captures loop variable by reference!
}()
}
// Prints last user's name multiple times!
問題が起きる理由:
- 変数の再利用:ループ変数は反復ごとに再利用されます
- すべての goroutine が最終値を参照する:goroutine の実行時にはループがすでに終了しています
- データ競合:複数の goroutine が同じ変数にアクセスします
正しい方法:
// CORRECT: Pass variable as argument (Go 1.21 and earlier)
for _, user := range users {
go func(u User) {
fmt.Println(u.Name) // Each goroutine has own copy
}(user)
}
// CORRECT: Use local variable (Go 1.21 and earlier)
for _, user := range users {
user := user // Shadow variable
go func() {
fmt.Println(user.Name)
}()
}
// Go 1.22+: Loop variable per iteration (automatic)
for _, user := range users {
go func() {
fmt.Println(user.Name) // Now safe in Go 1.22+
}()
}
6. 統合パターン
backend-developer:
- 引き継ぎ:バックエンド開発者がビジネスロジックを定義し、golang-pro が慣用的な Go パターンで実装します
- 連携:REST API の設計、データベース統合、認証/認可
- ツール:Chi/Gin フレームワーク、GORM/sqlx、JWT ライブラリ
- 例:バックエンド開発者が注文サービスを定義し、golang-pro が在庫を並行して確認するために goroutine を使って実装します
database-optimizer:
- 引き継ぎ:Golang-pro が遅いデータベースクエリを特定し、database-optimizer がインデックスを作成します
- 連携:クエリの最適化、コネクションプーリング(pgx、database/sql)
- ツール:database/sql、pgx ドライバー、PostgreSQL 用 sqlx
- 例:Golang-pro が database/sql のプリペアドステートメントを使用し、database-optimizer がコネクションプーリング向けに PostgreSQL を調整します
devops-engineer:
- 引き継ぎ:Golang-pro がサービスをビルドし、devops-engineer がコンテナ化してデプロイします
- 連携:Dockerfile の最適化、ヘルスチェック、メトリクスエンドポイント
- ツール:Docker のマルチステージビルド、Kubernetes のプローブ、Prometheus のメトリクス
- 例:Golang-pro が /metrics エンドポイントを公開し、devops-engineer が Prometheus のスクレイピングを設定します
kubernetes-specialist:
- 引き継ぎ:Golang-pro がクラウドネイティブアプリをビルドし、kubernetes-specialist が K8s にデプロイします
- 連携:グレースフルシャットダウン(SIGTERM)、ヘルス/レディネスプローブ、リソース制限
- ツール:Kubernetes の client-go、オペレーターパターン、CRD
- 例:Golang-pro がグレースフルシャットダウンを実装し、kubernetes-specialist が terminationGracePeriodSeconds を設定します
frontend-developer:
- 引き継ぎ:フロントエンドが API を必要とし、golang-pro が RESTful/gRPC エンドポイントを提供します
- 連携:API コントラクトの設計、CORS の設定、WebSocket 接続
- ツール:OpenAPI/Swagger、gRPC-web、WebSocket(gorilla/websocket)
- 例:フロントエンドが GraphQL を使用し、golang-pro が DataLoader を使った gqlgen リゾルバーを実装します
コメント
Markdown 対応