mcpField
G
go-best-practices

go-best-practices

github.com/alleneubank開発50359 回インストール18 週間前に更新
リポジトリ

go-best-practices について

go-best-practicesは、Go向けの言語別コーディングスキルです。CLAUDE.mdにある型優先、関数型、エラー処理のパターンに基づき、状態のモデル化、インターフェース、エラーチェーン、構造化ログを解説します。

主な機能

  1. 01ドメイン値に独自型を使う方法
  2. 02インターフェースによる振る舞いの定義
  3. 03関数オプションとコンポジションの適用
  4. 04エラーチェーンを保つラップ方法
  5. 05log/slogによる構造化ログ

活用シーン

  1. 01異なる型によるドメインIDのモデル化
  2. 02依存関係のインターフェース設計
  3. 03呼び出しをまたいだエラー情報の保持
  4. 04キーと値による構造化ログの追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/alleneubank/claude-code --skill go-best-practices

インストール後、Claude Code で/go-best-practicesを入力して読み込まれたか確認します。

詳細

Go のベストプラクティス

CLAUDE.md の型優先、関数型、エラー処理のパターンに従います。このスキルでは、言語固有のイディオムのみを扱います。

不正な状態を表現できないようにする

Go の型システムを使って、無効な状態をコンパイル時に防ぎます。

ドメインプリミティブにはカスタム型を使用します:

// Distinct types prevent mixing up IDs
type UserID string
type OrderID string

func GetUser(id UserID) (*User, error) {
    // Compiler prevents passing OrderID here
}

// Methods attach behavior to the type
func (id UserID) String() string {
    return string(id)
}

動作の契約にはインターフェースを使用します:

// Define what you need, not what you have
type UserRepository interface {
    GetByID(ctx context.Context, id UserID) (*User, error)
    Save(ctx context.Context, user *User) error
}

// Accept interfaces, return structs
func ProcessInput(r io.Reader) ([]byte, error) {
    return io.ReadAll(r)
}

iota と網羅的な switch を使った列挙型:

type Status int

const (
    StatusActive Status = iota + 1
    StatusInactive
    StatusPending
)

func ProcessStatus(s Status) (string, error) {
    switch s {
    case StatusActive:
        return "processing", nil
    case StatusInactive:
        return "skipped", nil
    case StatusPending:
        return "waiting", nil
    default:
        return "", fmt.Errorf("unhandled status: %v", s)
    }
}

柔軟な構築には関数型オプションを使用します:

type ServerOption func(*Server)

func WithPort(port int) ServerOption {
    return func(s *Server) { s.port = port }
}

func NewServer(opts ...ServerOption) *Server {
    s := &Server{port: 8080, timeout: 30 * time.Second}
    for _, opt := range opts {
        opt(s)
    }
    return s
}
// Usage: NewServer(WithPort(3000), WithTimeout(time.Minute))

構成には埋め込みを使用します:

type Timestamps struct {
    CreatedAt time.Time
    UpdatedAt time.Time
}

type User struct {
    Timestamps  // User gains CreatedAt, UpdatedAt
    ID    UserID
    Email string
}

Go 固有のエラー処理

%w でエラーをラップし、errors.Is / errors.As でチェーンを保持します:

out, err := client.Do(ctx, req)
if err != nil {
    return nil, fmt.Errorf("fetch widget failed: %w", err)
}

構造化ロギング

構造化されたキーと値のペアで log/slog を使用します:

import "log/slog"

var log = slog.With("component", "widgets")

func createWidget(name string) (*Widget, error) {
    log.Debug("creating widget", "name", name)
    widget := &Widget{Name: name}
    log.Debug("created widget", "id", widget.ID)
    return widget, nil
}

コメント