mcpField
G
golang-pro

golang-pro

github.com/404kidwiz開発113 回インストール
リポジトリ

golang-pro について

golang-proは、バックエンドサービス、コマンドラインツール、分散システムを開発するGo開発者向けのスキルです。Go 1.21以降、並行処理、性能改善、標準ライブラリの慣用的な使い方を扱います。

主な機能

  1. 01Go 1.21以降の言語ガイド
  2. 02goroutineとchannelの並行処理パターン
  3. 03バックエンドとネットワークサービスのパターン
  4. 04性能分析と最適化
  5. 05エラー処理とテストの実践

活用シーン

  1. 01並行処理を用いたGoサービスの構築
  2. 02コマンドラインツールの開発
  3. 03Goアプリケーションの性能改善
  4. 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 リゾルバーを実装します

コメント