ワンクリックで
go-patterns
Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable Go applications.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable Go applications.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Interactive installer for clarc — guides users through selecting and installing skills and rules to user-level or project-level directories, verifies paths, and optionally optimizes installed files.
Create zero-dependency, animation-rich HTML presentations from scratch or by converting PowerPoint/PPTX files. Use when the user wants to build a presentation, convert a deck to web, or create slides for a talk/pitch.
Create zero-dependency, animation-rich HTML presentations from scratch or by converting PowerPoint/PPTX files. Use when the user wants to build a presentation, convert a deck to web, or create slides for a talk/pitch.
Autonomous loop patterns for Claude — sequential pipelines, NanoClaw REPL, infinite agentic loops, continuous PR loops, De-Sloppify, and Ralphinho RFC-driven DAG orchestration. Pattern selection matrix and anti-patterns.
Create zero-dependency, animation-rich HTML presentations from scratch or by converting PowerPoint/PPTX files. Use when the user wants to build a presentation, convert a deck to web, or create slides for a talk/pitch.
Write-time code quality enforcement using Plankton — auto-formatting, linting, and Claude-powered fixes on every file edit via hooks.
| name | go-patterns |
| description | Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable Go applications. |
Idiomatic Go patterns and best practices for building robust, efficient, and maintainable applications.
Go favors simplicity over cleverness. Code should be obvious and easy to read.
// Good: Clear and direct
func 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 clever
func GetUser(id string) (*User, error) {
return func() (*User, error) {
if u, e := db.FindUser(id); e == nil {
return u, nil
} else {
return nil, e
}
}()
}
Design types so their zero value is immediately usable without initialization.
// Good: Zero value is useful
type 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 value
var buf bytes.Buffer
buf.WriteString("hello")
// Bad: Requires initialization
type BadCounter struct {
counts map[string]int // nil map will panic
}
Functions should accept interface parameters and return concrete types.
// Good: Accepts interface, returns concrete type
func 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) {
// ...
}
// Good: Wrap errors with context
func 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
}
// Define domain-specific errors
type 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 cases
var (
ErrNotFound = errors.New("resource not found")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidInput = errors.New("invalid input")
)
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)
}
// Bad: Ignoring error with blank identifier
result, _ := doSomething()
// Good: Handle or explicitly document why it's safe to ignore
result, err := doSomething()
if err != nil {
return err
}
// Acceptable: When error truly doesn't matter (rare)
_ = writer.Close() // Best-effort cleanup, error logged elsewhere
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)
}
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)
}
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")
}
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 {
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
}
Use a buffered channel and select with ctx.Done() so the goroutine can exit even if no receiver picks up the result:
func safeFetch(ctx context.Context, url string) <-chan []byte {
ch := make(chan []byte, 1) // Buffered — goroutine won't block
go func() {
data, err := fetch(url)
if err != nil { return }
select {
case ch <- data:
case <-ctx.Done(): // Exit if caller cancelled
}
}()
return ch
}
For advanced patterns covering interfaces (small focused interfaces, define-where-used, type assertions), package organization (hexagonal layout, naming conventions, avoiding package-level state), and full hexagonal architecture with working code — see
go-patterns-advanced.
Wrong: func NewUserService() UserServiceInterface { return &userServiceImpl{} }
Correct: func NewUserService(store UserStore) *UserService { return &UserService{store: store} }
Why: Returning interfaces forces a specific abstraction on callers; accept interfaces, return structs. Callers define the interfaces they need.
Wrong:
var db *sql.DB
func init() {
var err error
db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err) // Hard to test, no error propagation
}
}
Correct:
func NewServer(databaseURL string) (*Server, error) {
db, err := sql.Open("postgres", databaseURL)
if err != nil {
return nil, fmt.Errorf("open database: %w", err)
}
return &Server{db: db}, nil
}
Why: init() functions run silently at startup, cannot return errors cleanly, and make code untestable; explicit constructors with error returns are always preferable.
Wrong:
if err == sql.ErrNoRows {
// Misses wrapped errors
}
Correct:
if errors.Is(err, sql.ErrNoRows) {
// Works through any chain of wrapped errors
}
Why: The == operator only matches the exact error value and silently fails when the error has been wrapped with fmt.Errorf("...: %w", err).
Wrong:
func fetchData(url string) ([]byte, error) {
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
// cancel is discarded — context leaks until timeout
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
// ...
}
Correct:
func fetchData(url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // Always cancel to release resources immediately
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
// ...
}
Why: Discarding the cancel function keeps the context and its resources alive until the deadline, causing resource leaks especially in high-throughput code paths.
For advanced patterns — full hexagonal architecture with working code (domain, ports, adapters, DI wiring, tests), struct design (functional options, embedding), memory optimization, Go tooling,
slices/mapsstdlib (Go 1.21+), and anti-patterns — see skill:go-patterns-advanced. For testing patterns — table-driven tests, mocks, integration tests with testcontainers, benchmarks, and fuzz testing — see skill:go-testing.