К основному содержанию
скилл CX Codex

go-interface-design — скилл для Claude Code

Скилл помогает проектировать интерфейсы Go, разделять зависимости и проверять контракты на этапе компиляции. Пригодится при рефакторинге и подготовке к тестированию.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add eduardo-sl/go-agent-skills --skill go-interface-design -a claude-code
Открыть на GitHub

Что делает go-interface-design

Скилл подсказывает, где объявлять интерфейс, почему его лучше держать небольшим и когда вместо интерфейса оставить конкретную структуру. Он разбирает композицию интерфейсов, принцип «принимать интерфейсы, возвращать структуры» и проверку соответствия типа контракту при компиляции.

Есть и разбор ошибок: указателей на интерфейсы, преждевременных абстракций и interface{} без ясной причины. Подробные справочные материалы подключаются по мере необходимости. Для работы с проектом нужна Go toolchain; без неё команды go и gofmt не выполнятся.

Скилл рассчитан на проектирование интерфейсов и границ пакетов, а не на паттерны HTTP-обработчиков или общий код-ревью. Если в проекте есть правило агента, которое явно задаёт другие соглашения, оно имеет приоритет.

Какие задачи решает

  • определить интерфейс на стороне кода-потребителя
  • разбить широкий контракт на небольшие интерфейсы
  • проверить соответствие типа интерфейсу при компиляции
  • убрать указатель на интерфейс из сигнатуры функции
  • решить, нужна ли абстракция для единственной реализации

Примеры запросов агенту

  • Спроектируй интерфейс для сервиса, которому нужно только читать пользователя из хранилища.
  • Проверь, стоит ли разделить этот широкий интерфейс на несколько составных.
  • Добавь проверку на этапе компиляции, что PostgresStore реализует интерфейс потребителя.

Как установить go-interface-design

1Через Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-interface-design -a claude-code

2Вручную: положить файлы

~/.claude/skills/go-interface-design/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/go-interface-design/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о go-interface-design

Как установить go-interface-design в Claude Code?

Выполните npx skills add eduardo-sl/go-agent-skills --skill go-interface-design -a claude-code. Файл скилла находится по пути ~/.claude/skills/go-interface-design/SKILL.md.

Что делает go-interface-design?

Помогает выбирать место и размер интерфейсов в Go, составлять их из меньших контрактов и проверять реализацию при компиляции. Также объясняет типичные ошибки проектирования.

Что нужно для работы go-interface-design?

Нужна Go toolchain. Скилл использует команды go и gofmt для работы с Go-проектом.

Исходный текст

SKILL.md · MIT
---
name: go-interface-design
description: >
  Go interface design patterns: implicit interfaces, consumer-side
  definition, interface compliance verification, composition, the
  accept-interfaces-return-structs principle, and common pitfalls. Use when
  designing interfaces, decoupling packages, defining contracts, reviewing
  interface usage, or refactoring for testability. Trigger examples: "design
  interface", "accept interfaces return structs", "interface compliance",
  "consumer-side interface", "interface composition".
  Not for: HTTP handler patterns (go-api-design), general review
  (go-code-review).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
  author: eduardo-sl
  version: "1.2.1"
---

# 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.

> Community default. A project skill or agent-config rule that explicitly
> supersedes `go-interface-design` takes precedence over this one.

Detailed reference material, loaded on demand:

- `references/embedding-and-assertions.md` — embedding vs named fields,
  interface-embedding test fakes, optional capabilities, sealed interfaces.

Read a reference file only when the summary below is not enough.

## 1. The Cardinal Rule: Define Interfaces at the Consumer

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

```go
// ❌ 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.

```go
// ✅ 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

```go
// ✅ 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:

```go
// 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

```go
// ❌ 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:

```go
// ✅ 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. Optional Configuration Is Not an Interface Problem

Optional constructor settings are not a reason to introduce an interface.
Use functional options or a config struct — the go-design-patterns skill
owns both and the trade-off between them.

## 8. Common Interface Anti-Patterns

### Premature interfaces:

```go
// ❌ 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:

```go
// ❌ 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
```

### Sealed interfaces vs enums:

A sealed interface — an unexported marker method, so only this package can
add variants — is the right tool for a closed set of variants that carry
different data, consumed with a type switch. When the variants carry no
data, use a typed constant enum instead. Example:
`references/embedding-and-assertions.md`.

## 9. Embedding and Type Assertions

- Embedding promotes the whole method set. Embedding `sync.Mutex` in an
  exported struct publishes `Lock`/`Unlock`; use a named field unless the
  outer type truly *is* the inner one, extended.
- An interface embedded in a struct satisfies it with methods that panic
  when called — fine for test fakes, a hidden runtime failure elsewhere.
- Assert to an interface for optional capabilities
  (`w.(http.Flusher)`), always with comma-ok.
- Generic methods (Go 1.27+) never satisfy an interface method; keep the
  methods of anything you define as an interface non-generic.

## 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)`
6. **Am I embedding for convenience?** — named field unless every promoted method belongs on the outer type.

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Похожие скиллы

Всё по теме «Дизайн» →
frontend-design официальный anthropics Скилл задаёт осмысленное визуальное направление для новых интерфейсов и редизайна. Подойдёт, когда стандартный шаблонный UI не устраивает. 1 025 790установок grill-me Matt Pocock Скилл проводит жёсткое интервью по плану или дизайну, чтобы найти пробелы и уточнить решения. Подойдёт перед началом разработки. 1 424 476установок design-taste-frontend Leonxlnx Скилл задаёт арт-дирекцию для публичных страниц и рабочих экранов, а затем проверяет результат в браузере по скриншотам. Нужен, когда интерфейс выглядит шаблонным или недоработанным. CX Codex +1 678 700установок prototype Matt Pocock Создаёт временный прототип, чтобы проверить логику, модель состояния или вид интерфейса до работы над основным кодом. 986 201установок grilling Matt Pocock Стресс-тестирует план, решение или идею сериями уточняющих вопросов. Подходит, когда нужно вскрыть допущения до начала работы. 979 543установок codebase-design Matt Pocock Скилл помогает проектировать модули с небольшим интерфейсом и скрытой внутри сложностью. Подходит для рефакторинга, тестируемости и поиска чистого seam. 850 344установок

Из того же набора22

go-data-structures Скилл помогает выбирать и безопасно использовать слайсы, карты и массивы в Go. Пригодится, когда нужно разобраться с append, nil-слайсами или порядком обхода карты. CX Codex +1 ★ 83звёзд репо go-context Скилл для ИИ-агента, который проверяет и правит работу с context.Context в Go: отмена, таймауты, значения, типичные ошибки. CX Codex +1 ★ 83звёзд репо go-code-review Скилл проверяет Go-код и PR по структурированному списку: от обработки ошибок до тестов. Запускайте его перед слиянием изменений или для ревью пакета. CX Codex +1 ★ 83звёзд репо go-project-layout Подсказывает, как разложить новый Go-проект по папкам: cmd/, internal/, плоская раскладка для мелких утилит. Пригодится в самом начале, когда структура ещё не сложилась. CX Codex +1 ★ 83звёзд репо go-grpc Скилл для ИИ-агента, который ведёт разработку gRPC-сервисов на Go: proto-контракты, коды ошибок, дедлайны, интерцепторы и стриминг. CX Codex +1 ★ 83звёзд репо go-design-patterns Скилл помогает выбрать идиоматичный паттерн Go для создания объектов, смены поведения и обработки сбоев. Пригодится, когда нужно решить, как структурировать код. CX Codex +1 ★ 83звёзд репо go-dependency-injection Скилл учит агента внедрять зависимости в Go через конструкторы и собирать всё в main. Пригодится, когда в проекте завёлся глобальный синглтон или код тяжело тестировать. CX Codex +1 ★ 83звёзд репо go-architecture-review Скилл проверяет структуру пакетов, направление зависимостей и границы модулей в Go-проекте. Пригодится для ревью архитектуры или плана рефакторинга. CX Codex +1 ★ 83звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой