オプション
家 Skill テストとQA golang-patterns

堅牢で効率的、かつ保守性の高いGoアプリケーションを構築するための、Go特有のパターン、ベストプラクティス、および規約。

...すべて拡張します
41
更新された時間 2026年6月29日

概要golang-patterns

golang-patterns は、特定のワークフローに特化した再利用可能なAIスキルです。名称:golang-patterns

このスキルには、手順、規約、およびタスク固有のガイダンスがまとめられており、エージェントがより一貫性を持って作業を実行できるようになっています。説明: 堅牢で効率的、かつ保守性の高いGoアプリケーションを構築するための、Goのイディオム的なパターン、ベストプラクティス、および規約。堅牢で効率的、かつ保守性の高いアプリケーションを構築するための、Goのイディオム的なパターンとベストプラクティス。 - 新しいGoコードの記述

実際には、このスキルは、セットアップの手順を最小限に抑え、曖昧さを減らして繰り返し実行できる環境を必要とするユーザーに最適です。 - 既存のGoコードのリファクタリング - Goパッケージ/モジュールの設計 Goは、巧妙さよりもシンプルさを重視します。コードは直感的で読みやすいものであるべきです。 // 良い例:明確で直接的

よくある質問

golang-patterns はどのような点で役立ちますか?

golang-patterns エージェントがソースドキュメントに記載された集中型のワークフローに従うのを支援し、曖昧さを減らし、実行が意図されたタスクに沿ったものになるようにします。

このスキルはどのような場合に使用すべきですか?

タスクがスキルのドキュメントに記載されているワークフロー、ドメイン、または運用ルールに合致する場合、特に一貫した実行が重要な場合に使用してください。

主な制限事項は何ですか?

このスキルは、ソースとなる指示の質と範囲によって制約を受けます。基礎となるドキュメントが不完全な場合、エージェントは追加のコンテキスト情報や手動による検証を必要とする可能性があります。

GitHubで見る

Go Development Patterns

Idiomatic Go patterns and best practices for building robust, efficient, and maintainable applications.

When to Activate

  • Writing new Go code
  • Reviewing Go code
  • Refactoring existing Go code
  • Designing Go packages/modules

Core Principles

1. Simplicity and Clarity

Go favors simplicity over cleverness. Code should be obvious and easy to read.

// Good: Clear and directfunc GetUser(id string) (*User, error) {    user, err := db.FindUser(id)    if err != nil {        return nil, fmt.Errorf("get user %s: %w", id, err)    }    return user, nil}// Bad: Overly cleverfunc GetUser(id string) (*User, error) {    return func() (*User, error) {        if u, e := db.FindUser(id); e == nil {            return u, nil        } else {            return nil, e        }    }()}

2. Make the Zero Value Useful

Design types so their zero value is immediately usable without initialization.

// Good: Zero value is usefultype Counter struct {    mu    sync.Mutex    count int // zero value is 0, ready to use}func (c *Counter) Inc() {    c.mu.Lock()    c.count++    c.mu.Unlock()}// Good: bytes.Buffer works with zero valuevar buf bytes.Bufferbuf.WriteString("hello")// Bad: Requires initializationtype BadCounter struct {    counts map[string]int // nil map will panic}

3. Accept Interfaces, Return Structs

Functions should accept interface parameters and return concrete types.

// Good: Accepts interface, returns concrete typefunc ProcessData(r io.Reader) (*Result, error) {    data, err := io.ReadAll(r)    if err != nil {        return nil, err    }    return &Result{Data: data}, nil}// Bad: Returns interface (hides implementation details unnecessarily)func ProcessData(r io.Reader) (io.Reader, error) {    // ...}

Error Handling Patterns

Error Wrapping with Context

// Good: Wrap errors with contextfunc LoadConfig(path string) (*Config, error) {    data, err := os.ReadFile(path)    if err != nil {        return nil, fmt.Errorf("load config %s: %w", path, err)    }    var cfg Config    if err := json.Unmarshal(data, &cfg); err != nil {        return nil, fmt.Errorf("parse config %s: %w", path, err)    }    return &cfg, nil}

Custom Error Types

// Define domain-specific errorstype ValidationError struct {    Field   string    Message string}func (e *ValidationError) Error() string {    return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)}// Sentinel errors for common casesvar (    ErrNotFound     = errors.New("resource not found")    ErrUnauthorized = errors.New("unauthorized")    ErrInvalidInput = errors.New("invalid input"))

Error Checking with errors.Is and errors.As

func HandleError(err error) {    // Check for specific error    if errors.Is(err, sql.ErrNoRows) {        log.Println("No records found")        return    }    // Check for error type    var validationErr *ValidationError    if errors.As(err, &validationErr) {        log.Printf("Validation error on field %s: %s",            validationErr.Field, validationErr.Message)        return    }    // Unknown error    log.Printf("Unexpected error: %v", err)}

Never Ignore Errors

// Bad: Ignoring error with blank identifierresult, _ := doSomething()// Good: Handle or explicitly document why it's safe to ignoreresult, err := doSomething()if err != nil {    return err}// Acceptable: When error truly doesn't matter (rare)_ = writer.Close() // Best-effort cleanup, error logged elsewhere

Concurrency Patterns

Worker Pool

func WorkerPool(jobs <-chan Job, results chan<- Result, numWorkers int) {    var wg sync.WaitGroup    for i := 0; i < numWorkers; i++ {        wg.Add(1)        go func() {            defer wg.Done()            for job := range jobs {                results <- process(job)            }        }()    }    wg.Wait()    close(results)}

Context for Cancellation and Timeouts

func FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)    defer cancel()    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)    if err != nil {        return nil, fmt.Errorf("create request: %w", err)    }    resp, err := http.DefaultClient.Do(req)    if err != nil {        return nil, fmt.Errorf("fetch %s: %w", url, err)    }    defer resp.Body.Close()    return io.ReadAll(resp.Body)}

Graceful Shutdown

func GracefulShutdown(server *http.Server) {    quit := make(chan os.Signal, 1)    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)    <-quit    log.Println("Shutting down server...")    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)    defer cancel()    if err := server.Shutdown(ctx); err != nil {        log.Fatalf("Server forced to shutdown: %v", err)    }    log.Println("Server exited")}

errgroup for Coordinated Goroutines

import "golang.org/x/sync/errgroup"func FetchAll(ctx context.Context, urls []string) ([][]byte, error) {    g, ctx := errgroup.WithContext(ctx)    results := make([][]byte, len(urls))    for i, url := range urls {        i, url := i, url // Capture loop variables        g.Go(func() error {            data, err := FetchWithTimeout(ctx, url)            if err != nil {                return err            }            results[i] = data            return nil        })    }    if err := g.Wait(); err != nil {        return nil, err    }    return results, nil}

Avoiding Goroutine Leaks

// Bad: Goroutine leak if context is cancelledfunc leakyFetch(ctx context.Context, url string) <-chan []byte {    ch := make(chan []byte)    go func() {        data, _ := fetch(url)        ch <- data // Blocks forever if no receiver    }()    return ch}// Good: Properly handles cancellationfunc safeFetch(ctx context.Context, url string) <-chan []byte {    ch := make(chan []byte, 1) // Buffered channel    go func() {        data, err := fetch(url)        if err != nil {            return        }        select {        case ch <- data:        case <-ctx.Done():        }    }()    return ch}

Interface Design

Small, Focused Interfaces

// Good: Single-method interfacestype Reader interface {    Read(p []byte) (n int, err error)}type Writer interface {    Write(p []byte) (n int, err error)}type Closer interface {    Close() error}// Compose interfaces as neededtype ReadWriteCloser interface {    Reader    Writer    Closer}

Define Interfaces Where They're Used

// In the consumer package, not the providerpackage service// UserStore defines what this service needstype UserStore interface {    GetUser(id string) (*User, error)    SaveUser(user *User) error}type Service struct {    store UserStore}// Concrete implementation can be in another package// It doesn't need to know about this interface

Optional Behavior with Type Assertions

type Flusher interface {    Flush() error}func WriteAndFlush(w io.Writer, data []byte) error {    if _, err := w.Write(data); err != nil {        return err    }    // Flush if supported    if f, ok := w.(Flusher); ok {        return f.Flush()    }    return nil}

Package Organization

Standard Project Layout

myproject/├── cmd/│   └── myapp/│       └── main.go           # Entry point├── internal/│   ├── handler/              # HTTP handlers│   ├── service/              # Business logic│   ├── repository/           # Data access│   └── config/               # Configuration├── pkg/│   └── client/               # Public API client├── api/│   └── v1/                   # API definitions (proto, OpenAPI)├── testdata/                 # Test fixtures├── go.mod├── go.sum└── Makefile

Package Naming

// Good: Short, lowercase, no underscorespackage httppackage jsonpackage user// Bad: Verbose, mixed case, or redundantpackage httpHandlerpackage json_parserpackage userService // Redundant 'Service' suffix

Avoid Package-Level State

// Bad: Global mutable statevar db *sql.DBfunc init() {    db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))}// Good: Dependency injectiontype Server struct {    db *sql.DB}func NewServer(db *sql.DB) *Server {    return &Server{db: db}}

Struct Design

Functional Options Pattern

type Server struct {    addr    string    timeout time.Duration    logger  *log.Logger}type Option func(*Server)func WithTimeout(d time.Duration) Option {    return func(s *Server) {        s.timeout = d    }}func WithLogger(l *log.Logger) Option {    return func(s *Server) {        s.logger = l    }}func NewServer(addr string, opts ...Option) *Server {    s := &Server{        addr:    addr,        timeout: 30 * time.Second, // default        logger:  log.Default(),    // default    }    for _, opt := range opts {        opt(s)    }    return s}// Usageserver := NewServer(":8080",    WithTimeout(60*time.Second),    WithLogger(customLogger),)

Embedding for Composition

type Logger struct {    prefix string}func (l *Logger) Log(msg string) {    fmt.Printf("[%s] %s", l.prefix, msg)}type Server struct {    *Logger // Embedding - Server gets Log method    addr    string}func NewServer(addr string) *Server {    return &Server{        Logger: &Logger{prefix: "SERVER"},        addr:   addr,    }}// Usages := NewServer(":8080")s.Log("Starting...") // Calls embedded Logger.Log

Memory and Performance

Preallocate Slices When Size is Known

// Bad: Grows slice multiple timesfunc processItems(items []Item) []Result {    var results []Result    for _, item := range items {        results = append(results, process(item))    }    return results}// Good: Single allocationfunc processItems(items []Item) []Result {    results := make([]Result, 0, len(items))    for _, item := range items {        results = append(results, process(item))    }    return results}

Use sync.Pool for Frequent Allocations

var bufferPool = sync.Pool{    New: func() interface{} {        return new(bytes.Buffer)    },}func ProcessRequest(data []byte) []byte {    buf := bufferPool.Get().(*bytes.Buffer)    defer func() {        buf.Reset()        bufferPool.Put(buf)    }()    buf.Write(data)    // Process...    return buf.Bytes()}

Avoid String Concatenation in Loops

// Bad: Creates many string allocationsfunc join(parts []string) string {    var result string    for _, p := range parts {        result += p + ","    }    return result}// Good: Single allocation with strings.Builderfunc join(parts []string) string {    var sb strings.Builder    for i, p := range parts {        if i > 0 {            sb.WriteString(",")        }        sb.WriteString(p)    }    return sb.String()}// Best: Use standard libraryfunc join(parts []string) string {    return strings.Join(parts, ",")}

Go Tooling Integration

Essential Commands

# Build and rungo build ./...go run ./cmd/myapp# Testinggo test ./...go test -race ./...go test -cover ./...# Static analysisgo vet ./...staticcheck ./...golangci-lint run# Module managementgo mod tidygo mod verify# Formattinggofmt -w .goimports -w .

Recommended Linter Configuration (.golangci.yml)

linters:  enable:    - errcheck    - gosimple    - govet    - ineffassign    - staticcheck    - unused    - gofmt    - goimports    - misspell    - unconvert    - unparamlinters-settings:  errcheck:    check-type-assertions: true  govet:    check-shadowing: trueissues:  exclude-use-default: false

Quick Reference: Go Idioms

IdiomDescription
Accept interfaces, return structsFunctions accept interface params, return concrete types
Errors are valuesTreat errors as first-class values, not exceptions
Don't communicate by sharing memoryUse channels for coordination between goroutines
Make the zero value usefulTypes should work without explicit initialization
A little copying is better than a little dependencyAvoid unnecessary external dependencies
Clear is better than cleverPrioritize readability over cleverness
gofmt is no one's favorite but everyone's friendAlways format with gofmt/goimports
Return earlyHandle errors first, keep happy path unindented

Anti-Patterns to Avoid

// Bad: Naked returns in long functionsfunc process() (result int, err error) {    // ... 50 lines ...    return // What is being returned?}// Bad: Using panic for control flowfunc GetUser(id string) *User {    user, err := db.Find(id)    if err != nil {        panic(err) // Don't do this    }    return user}// Bad: Passing context in structtype Request struct {    ctx context.Context // Context should be first param    ID  string}// Good: Context as first parameterfunc ProcessRequest(ctx context.Context, id string) error {    // ...}// Bad: Mixing value and pointer receiverstype Counter struct{ n int }func (c Counter) Value() int { return c.n }    // Value receiverfunc (c *Counter) Increment() { c.n++ }        // Pointer receiver// Pick one style and be consistent

Remember: Go code should be boring in the best way - predictable, consistent, and easy to understand. When in doubt, keep it simple.

すべてのファイル

1件のファイル

golang-patternsをインストール

スキルファイルをダウンロードし、.claude/skills/ ディレクトリに解凍してください。

ZIPをダウンロード

リポジトリをクローンし、スキルファイルをプロジェクトにコピーしてください。

git clone https://github.com/affaan-m/ECC/blob/main/skills/golang-patterns/SKILL.md # Copy SKILL.md to your .claude/skills/ directory

コピー コピー
クイックセットアップ: skillフォルダを.claude/skills/にコピーしてください。Claudeが自動的にそのスキルを検出して使用します。

関連スキル

golang-structs-interfaces
更新された時間 2026年6月29日
OR