MCP HubMCP Hub
SKILL·E8FE9F

go-interface-design

eduardo-sl
更新日 27 days ago
6 閲覧
69
9
69
GitHubで表示
テストtestingapidesign

について

このスキルは、Go言語におけるインターフェース設計パターンについてのガイダンスを提供します。暗黙的インターフェース、利用者側での定義、「インターフェースを受け取り構造体を返す」原則などを含みます。インターフェース設計、パッケージの分離、契約の定義、テスト容易性のためのリファクタリングを行う際にご利用ください。インターフェースの合成、準拠の検証、回避すべき一般的な落とし穴についても扱っています。

クイックインストール

Claude Code

推奨
メイン
npx skills add eduardo-sl/go-agent-skills -a claude-code
プラグインコマンド代替
/plugin add https://github.com/eduardo-sl/go-agent-skills
Git クローン代替
git clone https://github.com/eduardo-sl/go-agent-skills.git ~/.claude/skills/go-interface-design

このコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします

ドキュメント

Go Interface Design

Go interfaces are implicit. This is the single most important design feature of the language, and most people coming from Java or C# get it wrong at first.

1. The Cardinal Rule: Define Interfaces at the Consumer

The consumer of a behavior defines the interface, NOT the provider:

// ❌ Wrong — producer defines interface (Java thinking)
// package store
type UserStore interface {      // defined alongside implementation
    GetByID(ctx context.Context, id string) (*User, error)
    Create(ctx context.Context, user *User) error
    // ... 15 more methods
}

type PostgresStore struct { ... }
func (s *PostgresStore) GetByID(...) { ... }
func (s *PostgresStore) Create(...) { ... }

// ✅ Right — consumer defines what it needs
// package service
type UserReader interface {     // only what THIS service needs
    GetByID(ctx context.Context, id string) (*domain.User, error)
}

type UserService struct {
    store UserReader  // depends on narrow interface
}

// package store (no interface defined here)
type PostgresStore struct { db *sql.DB }
func (s *PostgresStore) GetByID(ctx context.Context, id string) (*domain.User, error) { ... }
func (s *PostgresStore) Create(ctx context.Context, user *domain.User) error { ... }

// PostgresStore satisfies service.UserReader implicitly — no declaration needed

Why this matters:

  • Consumer depends only on what it uses (Interface Segregation Principle).
  • Producer can add methods without breaking consumers.
  • Testing requires only the methods the consumer calls.
  • No import cycle: consumer doesn't import producer's package.

2. Keep Interfaces Small

The bigger the interface, the weaker the abstraction.

// ✅ Good — focused, composable
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

// ❌ Bad — kitchen sink interface
type FileManager interface {
    Read(path string) ([]byte, error)
    Write(path string, data []byte) error
    Delete(path string) error
    List(dir string) ([]string, error)
    Move(src, dst string) error
    Copy(src, dst string) error
    Stat(path string) (os.FileInfo, error)
    Watch(path string) (<-chan Event, error)
}

Guideline: 1-3 methods is ideal. If you need more, compose smaller interfaces.

3. Accept Interfaces, Return Structs

// ✅ Good — accepts interface, returns concrete type
func NewUserService(store UserReader, logger Logger) *UserService {
    return &UserService{store: store, logger: logger}
}

// ❌ Bad — returns interface (hides the concrete type for no reason)
func NewUserService(store UserReader) UserServiceInterface {
    return &UserService{store: store}
}

Return a concrete type so callers get full access to the type's methods. Returning an interface only makes sense when the function genuinely returns different concrete types based on input (factory pattern).

4. Verify Interface Compliance at Compile Time

Use the blank identifier assignment to catch broken contracts early:

// Verify *PostgresStore implements service.UserReader at compile time
var _ service.UserReader = (*PostgresStore)(nil)

// Verify LogHandler implements http.Handler
var _ http.Handler = (*LogHandler)(nil)

// For value receivers:
var _ fmt.Stringer = Status(0)

Place these immediately after the type declaration. They cost nothing at runtime and prevent silent contract breakage.

5. Don't Use Pointers to Interfaces

// ❌ Bad — pointer to interface is almost never correct
func process(r *io.Reader) { ... }

// ✅ Good — interface is already a pointer internally
func process(r io.Reader) { ... }

An interface value is internally two pointers (type + data). A pointer to an interface is a pointer to a pointer — needless indirection.

The only exception: when you need to replace the interface value itself (swap the implementation at runtime), which is extremely rare.

6. The Empty Interface

interface{} (or any in Go 1.18+) means you've given up on type safety. Use it sparingly:

// ✅ Acceptable — generic container before generics / stdlib compatibility
func Marshal(v any) ([]byte, error)

// ✅ Better (Go 1.18+) — use generics instead of any
func Map[T, U any](slice []T, fn func(T) U) []U { ... }

// ❌ Bad — lazy interface design
func Process(data any) any { ... } // what does this even do?

7. Functional Options Pattern

When a constructor needs optional configuration, use functional options instead of a config struct with an interface:

type Option func(*Server)

func WithTimeout(d time.Duration) Option {
    return func(s *Server) { s.timeout = d }
}

func WithLogger(l Logger) Option {
    return func(s *Server) { s.logger = l }
}

func NewServer(addr string, opts ...Option) *Server {
    s := &Server{
        addr:    addr,
        timeout: 30 * time.Second,  // sensible default
        logger:  slog.Default(),    // default stdlib logger
    }
    for _, opt := range opts {
        opt(s)
    }
    return s
}

// Usage
srv := NewServer(":8080",
    WithTimeout(60 * time.Second),
    WithLogger(logger),
)

8. Common Interface Anti-Patterns

Premature interfaces:

// ❌ Bad — interface defined before second implementation exists
type Processor interface {
    Process(ctx context.Context, data []byte) error
}

type processor struct { ... }  // only one implementation ever

// ✅ Good — use concrete type until you need the abstraction
type Processor struct { ... }
// Add interface when you have 2+ implementations or need testing seam

"Don't design with interfaces, discover them." — Rob Pike

Interface pollution:

// ❌ Bad — wrapping every struct in an interface "for testability"
type UserServiceInterface interface { ... }
type OrderServiceInterface interface { ... }
type PaymentServiceInterface interface { ... }
// 50 more interfaces with exactly one implementation each

// ✅ Good — define interfaces where they're consumed
// Each consumer declares only the methods IT needs

Misusing interfaces for enums:

// ❌ Bad — interface used as enum/sum type
type Shape interface {
    isShape()
}
type Circle struct{}
func (Circle) isShape() {}

// ✅ Better — sealed interface pattern (if you need it)
// Or just use constants with a type
type ShapeKind int
const (
    ShapeCircle ShapeKind = iota
    ShapeRectangle
)

Decision Checklist

  1. Do I need an interface here? — Only if you have 2+ implementations, need a testing seam, or are crossing a package boundary.
  2. Where should it be defined? — At the consumer, not the producer.
  3. How many methods? — Fewer is better. 1-3 is ideal.
  4. Am I returning an interface? — Probably shouldn't. Return concrete.
  5. Have I verified compliance?var _ Interface = (*Type)(nil)

GitHub リポジトリ

eduardo-sl/go-agent-skills
パス: skills/(architecture)/go-interface-design
0
FAQ

よくある質問

go-interface-design Skillとは何ですか?

go-interface-design はeduardo-sl が作成した Claude Skillです。Skillは、Claudeが必要に応じて読み込む指示とリソースをまとめ、追加の指示なしで go-interface-design に関連するタスクを実行できるようにします。

go-interface-design をインストールするには?

このページのインストールコマンドを使用してください。go-interface-design をプラグインとして Claude Code に追加するか、リポジトリを skills ディレクトリにクローンし、Claudeを再起動してSkillを読み込みます。

go-interface-design はどのカテゴリに属しますか?

go-interface-design は テスト カテゴリに属します。

go-interface-design は無料で利用できますか?

はい。go-interface-design は AIMCP に掲載されており、無料でインストールできます。

関連スキル

evaluating-llms-harness
テスト

このClaudeスキルは、lm-evaluation-harnessを実行し、MMLUやGSM8Kなど60以上の標準化学術タスクでLLMをベンチマークします。開発者がモデルの品質を比較し、トレーニングの進捗を追跡し、学術的な結果を報告するために設計されています。このツールはHuggingFaceやvLLMモデルを含む様々なバックエンドをサポートしています。

スキルを見る
cloudflare-cron-triggers
テスト

このスキルは、cron式を使用してWorkersをスケジュールするためのCloudflare Cron Triggersの実装に関する包括的な知識を提供します。定期的なタスクの設定、メンテナンスジョブ、自動化されたワークフローの構築を網羅し、無効なcron式やタイムゾーン問題といった一般的な課題への対処法も含みます。開発者はこれを使用して、スケジュールされたハンドラーの設定、cronトリガーのテスト、WorkflowsやGreen Computeとの連携を構成できます。

スキルを見る
webapp-testing
テスト

このClaude Skillは、Playwrightベースのツールキットを提供し、Pythonスクリプトを通じてローカルWebアプリケーションのテストを可能にします。フロントエンドの検証、UIデバッグ、スクリーンショット撮影、ログ表示を実現し、サーバーライフサイクルを管理します。ブラウザ自動化タスクにご利用いただけますが、コンテキストの汚染を避けるため、スクリプトのソースコードを読むのではなく直接実行してください。

スキルを見る
finishing-a-development-branch
テスト

このスキルは、開発者がテストの合格を確認し、構造化された統合オプションを提示することで、完成した作業を仕上げることを支援します。実装が完了した後のマージ、PR作成、ブランチの整理といったワークフローを案内します。コードが準備できてテスト済みの際に使用し、開発プロセスを体系的に完了させましょう。

スキルを見る