4
0
Source

Use when building Go backend services, implementing goroutines/channels, handling errors idiomatically, writing tests with testify, or following Go best practices for APIs/CLI tools.

Install

mkdir -p .claude/skills/golang && curl -L -o skill.zip "https://mcp.directory/api/skills/download/9102" && unzip -o skill.zip -d .claude/skills/golang && rm skill.zip

Installs to .claude/skills/golang

About this skill

Go Development Best Practices

Version: 2.0.0 Purpose: Comprehensive Go development patterns covering idioms, error handling, concurrency, testing, and quality Scope: Backend development with Go - API services, CLI tools, system software Prerequisites: Basic Go syntax knowledge

Overview

Go (Golang) is designed for simplicity, explicit error handling, and safe concurrent programming. This skill covers production-ready patterns validated by the Go community, official documentation, and industry standards (Uber Engineering, Google).

Core Philosophy:

  • Simplicity: "Clear is better than clever" - favor readable code over abstractions
  • Explicit over implicit: No exceptions, no hidden control flow, visible errors
  • Composition over inheritance: Interfaces and embedding, not class hierarchies
  • Built-in concurrency: Goroutines and channels as first-class primitives
  • Tooling-first: Format, vet, test, and benchmark built into the language

Key Design Principles:

  1. Small interfaces (1-3 methods ideal)
  2. Consumer-side interface placement
  3. Error values, not exceptions
  4. Happy path at left margin
  5. Goroutines must have explicit termination

1. Idiomatic Go Patterns

1.1 Naming Conventions

Package Names:

// ✅ GOOD: Package names are single lowercase identifiers
// Import path: "net/url" → package name: url
// Import path: "encoding/json" → package name: json
package url      // from "net/url"
package json     // from "encoding/json"
package strings

// ❌ BAD
package urls            // No plural
package encodingjson    // Don't smash words together
package stringutils     // Too verbose

Getters and Setters:

type Account struct {
    balance int
}

// ✅ GOOD: No "Get" prefix
func (a *Account) Balance() int {
    return a.balance
}

func (a *Account) SetBalance(amount int) {
    a.balance = amount
}

// ❌ BAD: Java-style getters
func (a *Account) GetBalance() int {
    return a.balance
}

Error Variables:

// Exported sentinel errors (capitalized)
var ErrNotFound = errors.New("not found")
var ErrTimeout = errors.New("timeout")

// Unexported internal errors (lowercase)
var errInternal = errors.New("internal error")

Interface Naming:

// ✅ GOOD: Short, descriptive
type Reader interface {
    Read(p []byte) (n int, err error)
}

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

// ❌ BAD: Verbose or unclear
type DataReader interface { ... }
type IReader interface { ... }  // No "I" prefix

1.2 Interface Design - "The Bigger the Interface, the Weaker the Abstraction"

Core Principle: Small, consumer-side interfaces provide maximum flexibility.

Single-Method Interfaces (Ideal):

// Standard library examples
type Reader interface {
    Read(p []byte) (n int, err error)
}

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

type Closer interface {
    Close() error
}

// Compose interfaces
type ReadCloser interface {
    Reader
    Closer
}

Consumer-Side Interface Placement:

// ❌ WRONG: Producer defines interface
package store

type CustomerStorage interface {
    StoreCustomer(Customer) error
    GetCustomer(string) (Customer, error)
    UpdateCustomer(Customer) error
    // 10+ methods...
}

type PostgresStore struct {}
func (s *PostgresStore) StoreCustomer(...) { ... }

// ✅ CORRECT: Consumer defines what it needs
package client

type customerGetter interface {
    GetCustomer(string) (store.Customer, error)
}

func ProcessCustomer(cg customerGetter) {
    customer, _ := cg.GetCustomer("123")
    // Only depends on GetCustomer method
}

Return Concrete Types, Accept Interfaces (Postel's Law):

// ✅ GOOD
func NewStore() *PostgresStore {
    return &PostgresStore{}
}

func Process(storage CustomerStorage) error {
    // Accepts interface
}

// ❌ BAD: Returning interface
func NewStore() CustomerStorage {
    return &PostgresStore{}
}

When to Create Interfaces:

  • Multiple implementations exist or are planned
  • Need for testing (mocking dependencies)
  • Decoupling packages
  • NOT for: Single implementation with no testing need

1.3 Happy Path Left, Early Returns

Core Principle: Align success path to left margin, handle errors first.

// ❌ BAD: Deep nesting
func join(s1, s2 string, max int) (string, error) {
    if s1 == "" {
        return "", errors.New("s1 is empty")
    } else {
        if s2 == "" {
            return "", errors.New("s2 is empty")
        } else {
            concat, err := concatenate(s1, s2)
            if err != nil {
                return "", err
            } else {
                if len(concat) > max {
                    return concat[:max], nil
                } else {
                    return concat, nil
                }
            }
        }
    }
}

// ✅ GOOD: Happy path aligned left
func join(s1, s2 string, max int) (string, error) {
    if s1 == "" {
        return "", errors.New("s1 is empty")
    }
    if s2 == "" {
        return "", errors.New("s2 is empty")
    }

    concat, err := concatenate(s1, s2)
    if err != nil {
        return "", err
    }

    if len(concat) > max {
        return concat[:max], nil
    }
    return concat, nil
}

Guidelines:

  • Maximum 3-4 levels of nesting
  • Omit else blocks when if returns
  • Handle errors immediately
  • Keep normal flow at lowest indentation

1.4 Composition Over Inheritance

Type Embedding (Struct Composition):

// Embedding for method promotion
type Logger struct {
    *log.Logger
    prefix string
}

func NewLogger(prefix string) *Logger {
    return &Logger{
        Logger: log.New(os.Stdout, "", 0),
        prefix: prefix,
    }
}

// Logger methods automatically available
logger := NewLogger("APP")
logger.Println("message") // Calls embedded log.Logger.Println

Interface Composition:

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}

// Compose interfaces
type ReadCloser interface {
    Reader
    Closer
}

Warning: Avoid embedding in public APIs:

// ❌ BAD: Exposes implementation details
type MyHandler struct {
    http.Handler // Leaks all Handler methods
}

// ✅ GOOD: Explicit delegation
type MyHandler struct {
    handler http.Handler
}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Custom logic
    h.handler.ServeHTTP(w, r)
}

1.5 Key Go Idioms

Defer for Cleanup:

func processFile(path string) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close() // Guaranteed cleanup

    // Multiple returns, all close file
    if condition {
        return nil // File closed
    }

    return process(f) // File closed
}

// Mutex pattern
func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()

    c.value++ // All paths unlock
}

Critical Rule: Call defer AFTER checking error:

// ❌ WRONG
defer f.Close() // f is nil if Open failed
f, err := os.Open(path)

// ✅ CORRECT
f, err := os.Open(path)
if err != nil {
    return err
}
defer f.Close()

Multiple Return Values:

// (value, error) - Standard error handling
func GetUser(id string) (*User, error) {
    // ...
}

// (value, bool) - "comma ok" idiom
value, ok := myMap[key]
if !ok {
    // key not found
}

result, ok := someValue.(TargetType)
if !ok {
    // type assertion failed
}

data, ok := <-channel
if !ok {
    // channel closed
}

Blank Identifier _:

// Ignore unwanted values
_, err := os.Open(filename)

// Compile-time interface check
var _ http.Handler = (*MyHandler)(nil)

// Import for side effects
import _ "net/http/pprof"

Useful Zero Values:

// sync.Mutex - ready to use
var mu sync.Mutex
mu.Lock() // Works immediately

// bytes.Buffer - valid empty buffer
var buf bytes.Buffer
buf.WriteString("hello") // No initialization needed

// Slices - safe to read
var s []int
fmt.Println(len(s)) // 0 (safe)

2. Error Handling

2.1 Error Wrapping with %w (Go 1.13+)

Core Pattern: Wrap errors with context using fmt.Errorf and %w.

func processFile(path string) error {
    file, err := os.Open(path)
    if err != nil {
        // Wrap with context using %w
        return fmt.Errorf("failed to open file %s: %w", path, err)
    }
    defer file.Close()

    data, err := io.ReadAll(file)
    if err != nil {
        return fmt.Errorf("failed to read file %s: %w", path, err)
    }

    return processData(data)
}

// Result when error bubbles up:
// "failed to initialize: failed to open file config.json: open config.json: no such file or directory"

Checking Wrapped Errors:

// errors.Is - Check for specific error in chain
if errors.Is(err, os.ErrNotExist) {
    fmt.Println("File doesn't exist")
}

// errors.As - Extract specific error type
var pathErr *os.PathError
if errors.As(err, &pathErr) {
    fmt.Printf("Path error on: %s\n", pathErr.Path)
}

Critical: Use %w, NOT %v:

// ❌ WRONG: Breaks error chain
return fmt.Errorf("failed: %v", err)

// ✅ CORRECT: Preserves chain
return fmt.Errorf("failed: %w", err)

2.2 Sentinel Errors vs Custom Error Types

Sentinel Errors (Package-Level Variables):

package db

var (
    ErrConnectionFailed = errors.New("database connection failed")
    ErrRecordNotFound   = errors.New("record not found")
    ErrDuplicateKey     = errors.New("duplicate key violation")
)

func GetUser(id int) (*User, error) {
    // ...
    if notFound {
        return nil, ErrRecordNotFound
    }
    return user, nil
}

// Caller checks with errors.Is
user, err := db.GetUser(123)
if errors.Is(err, db.ErrRecordNotFound) {
    // Handle not found
}

Custom Error Types (Rich Context):

type ValidationError struct {
    Field   string
    Value   interface{}
    Message string
}

fun

---

*Content truncated.*

claudish-usage

MadAppGang

CRITICAL - Guide for using Claudish CLI ONLY through sub-agents to run Claude Code with any AI model (OpenRouter, Gemini, OpenAI, local models). NEVER run Claudish directly in main context unless user explicitly requests it. Use when user mentions external AI models, Claudish, OpenRouter, Gemini, OpenAI, Ollama, or alternative models. Includes mandatory sub-agent delegation patterns, agent selection guide, file-based instructions, and strict rules to prevent context window pollution.

363

schemas

MadAppGang

YAML frontmatter schemas for Claude Code agents and commands. Use when creating or validating agent/command files.

13

external-model-selection

MadAppGang

Choose optimal external AI models for code analysis, bug investigation, and architectural decisions. Use when consulting multiple LLMs via claudish, comparing model perspectives, or investigating complex Go/LSP/transpiler issues. Provides empirically validated model rankings (91/100 for MiniMax M2, 83/100 for Grok Code Fast) and proven consultation strategies based on real-world testing.

172

hierarchical-coordinator

MadAppGang

Prevent goal drift in long-running multi-agent workflows using a coordinator agent that validates outputs against original objectives at checkpoints. Use when orchestrating 3+ agents, multi-phase features, complex implementations, or any workflow where agents may lose sight of original requirements. Trigger keywords - "hierarchical", "coordinator", "anti-drift", "checkpoint", "validation", "goal-alignment", "decomposition", "phase-gate", "shared-state", "drift detection".

21

email-deliverability

MadAppGang

Email deliverability best practices and troubleshooting

01

adr-documentation

MadAppGang

Architecture Decision Records (ADR) documentation practice. Use when documenting architectural decisions, recording technical trade-offs, creating decision logs, or establishing architectural patterns. Trigger keywords - "ADR", "architecture decision", "decision record", "trade-offs", "architectural decision", "decision log".

11

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

1,4071,302

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

1,2201,024

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

9001,013

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

958658

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

970608

pdf-to-markdown

aliceisjustplaying

Convert entire PDF documents to clean, structured Markdown for full context loading. Use this skill when the user wants to extract ALL text from a PDF into context (not grep/search), when discussing or analyzing PDF content in full, when the user mentions "load the whole PDF", "bring the PDF into context", "read the entire PDF", or when partial extraction/grepping would miss important context. This is the preferred method for PDF text extraction over page-by-page or grep approaches.

1,033496

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.