SKILL·E8FE9F

go-interface-design

eduardo-sl
更新于 8 days ago
64
9
64
在 GitHub 上查看
测试testingapidesign

关于

This skill provides guidance on Go interface design patterns including implicit interfaces, consumer-side definition, and the accept-interfaces-return-structs principle. Use it when designing interfaces, decoupling packages, defining contracts, or refactoring for testability. It covers interface composition, compliance verification, and common pitfalls to avoid.

快速安装

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 是一个 Claude Skill,作者为 eduardo-sl。Skill 将 Claude 按需加载的说明和资源打包,让 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
测试

该Skill通过60+个学术基准测试(如MMLU、GSM8K等)评估大语言模型质量,适用于模型对比、学术研究及训练进度追踪。它支持HuggingFace、vLLM和API接口,被EleutherAI等行业领先机构广泛采用。开发者可通过简单命令行快速对模型进行多任务批量评估。

查看技能
cloudflare-cron-triggers
测试

这个Claude Skill提供了关于Cloudflare Cron Triggers的完整知识库,用于通过cron表达式定时执行Workers。它支持配置周期性任务、维护作业和自动化工作流,并能处理常见的cron触发错误。开发者可以用它来设置定时任务、测试cron处理器,并集成Workflows和Green Compute功能。

查看技能
webapp-testing
测试

该Skill为开发者提供了基于Playwright的本地Web应用测试工具集,支持自动化测试前端功能、调试UI行为、捕获屏幕截图和查看浏览器日志。它包含管理服务器生命周期的辅助脚本,可直接作为黑盒工具运行而无需阅读源码。适用于需要快速验证本地Web应用界面和交互功能的开发场景。

查看技能
finishing-a-development-branch
测试

这个Skill用于开发分支完成后的集成决策,当代码实现完成且测试通过时,它会引导开发者选择合适的工作流。它首先验证测试状态,然后提供合并、创建PR或清理等结构化选项。核心价值在于确保代码质量的同时,标准化分支收尾流程。

查看技能