agentsclimarketplace

Effective go

Skill radkomih/claude-code-ext/plugins/effective-go/skills/effective-go

Claude Code Plugins

Install
npx -y skills add radkomih/claude-code-ext --skill effective-go

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Analyzes and refactors Go code using Effective Go principles. Use whenever Go code is written, reviewed, or modified — including goroutine issues, error handling, naming, interfaces, or formatting. Also trigger when the user asks whether their Go code is idiomatic, even without mentioning "Effective Go" by name.

SKILL.md

13.9 KB, ~3.4k tokens by cl100k_base, as published. Nobody here has run it

Effective Go Skill

Comprehensive Go refactoring framework based on the official Effective Go guide and Go best practices.

Prerequisites

Always read resources/effective-go-principles.json (in this skill's directory) before starting.

It contains 25+ principles with definitions, code smells, and refactoring guidance including:

  • Formatting (gofmt, semicolons)
  • Naming (packages, interfaces, exported names)
  • Control structures (if, for, switch, defer)
  • Data structures (slices, maps, arrays)
  • Functions (multiple returns, named returns, defer)
  • Concurrency (goroutines, channels, select)
  • Error handling (error vs panic, wrapping)
  • Interfaces and methods (receivers, embedding)

Refactoring Approach

Four-Phase Strategy

Phase 1: Discovery & Analysis (15-20 min)

Understand the Codebase:

  1. Identify scope (package, module, or entire project)
  2. Check Go version and module structure
  3. Analyze existing code patterns
  4. Review dependencies and imports

Scan for Code Smells:

  • No gofmt/goimports formatting
  • Non-idiomatic naming (snake_case, wrong capitalization)
  • Wrong receiver types (value when pointer needed)
  • Missing error checks
  • Goroutine leaks or race conditions
  • Improper channel usage
  • Panic in library code
  • Mutable value types that should be immutable
  • Large interfaces (>3 methods for non-standard libs)
  • Primitive obsession (no custom types)

Technical Exploration — search and run:

  • Run gofmt -l . | grep -v "vendor/" — check formatting
  • Pattern ^func [a-z] in *.go files — find unexported funcs that may need export
  • Pattern ^type [a-z] — find unexported types
  • Pattern go func in *.go files — find goroutine launches
  • Pattern err := — find error assignments
  • Pattern panic\( — find panic usage in library code
  • Pattern type.*interface — find interface definitions

Phase 2: Strategic Refactoring Plan (10-15 min)

Based on loaded Effective Go principles:

  1. Formatting and Style

    • Run gofmt/goimports on all files
    • Fix semicolon issues
    • Ensure proper brace placement
    • Clean up whitespace
  2. Naming Conventions

    • Fix package names (lowercase, single-word)
    • Correct exported/unexported names
    • Apply MixedCaps/mixedCaps consistently
    • Rename interfaces (-er suffix for single-method)
  3. Prioritize Refactoring

    • Critical: gofmt, data races, goroutine leaks, missing error checks
    • High: Wrong receivers, panic in libraries, improper channel usage
    • Medium: Non-idiomatic naming, primitive obsession, large interfaces
    • Low: Style improvements, comment formatting

Phase 3: Tactical Pattern Application (30-45 min)

Apply patterns systematically:

1. Formatting

  • Run gofmt -w on all Go files
  • Ensure tabs for indentation
  • Fix opening brace placement
  • Remove unnecessary semicolons

2. Naming

  • Package names: short, lowercase, no underscores
  • Exported names: Start with uppercase
  • Unexported names: Start with lowercase
  • Interfaces: Use -er suffix (Reader, Writer, Closer)
  • No snake_case: Use MixedCaps or mixedCaps
  • Acronyms: All caps (HTTP, URL, ID)

3. Control Structures

  • Use guard clauses (early returns)
  • Prefer for range over traditional for loops
  • Use expression-less switch for if-else chains
  • Apply defer for cleanup operations
  • Avoid naked returns in long functions

4. Error Handling

  • Check all errors explicitly
  • Add context with fmt.Errorf and %w
  • Return errors, don't panic (except in truly exceptional cases)
  • Use errors.Is and errors.As for error checking
  • Implement error wrapping consistently

5. Concurrency

  • Fix goroutine leaks (ensure they can exit)
  • Use channels for communication
  • Apply proper channel closing (sender closes)
  • Use select for multiplexing
  • Avoid shared memory, prefer channels
  • Add sync.WaitGroup for coordination
  • Fix loop variable capture in goroutines (only an issue pre-Go 1.22; check go.mod)

6. Pointers vs Values

  • Use pointer receivers when modifying receiver
  • Use pointer receivers for large structs
  • Be consistent (all pointer or all value for a type)
  • Use pointer receivers for types with sync.Mutex

7. Interfaces

  • Keep interfaces small (1-3 methods ideal)
  • Define interfaces where used, not where implemented
  • Accept interfaces, return structs
  • Use empty interface sparingly

8. Data Structures

  • Prefer slices over arrays
  • Use make() with capacity hints
  • Ensure maps are initialized with make()
  • Use composite literals for initialization
  • Apply append() correctly (assign result)

Phase 4: Validation & Testing (10-15 min)

Verify Improvements:

  • All files pass gofmt check
  • No exported names start with lowercase
  • All errors are checked or explicitly ignored
  • No goroutine leaks detected
  • Channels properly closed from sender
  • Receiver types are consistent and appropriate
  • No panic calls in library code
  • Interfaces are small and focused
  • Code follows Go idioms

Testing Strategy:

  • Run go vet on all packages
  • Run golint or staticcheck
  • Run go test -race to detect data races
  • Use go test -cover for coverage
  • Run golangci-lint for comprehensive checks

Core Effective Go Principles Reference

Formatting

  1. gofmt - Standard formatting, non-negotiable
  2. Semicolons - Automatic insertion, placement rules

Naming

  1. Package Names - Short, lowercase, single-word
  2. Exported Names - Uppercase = public
  3. Interface Naming - -er suffix for single-method
  4. MixedCaps - No underscores in identifiers

Control Structures

  1. Guard Clauses - Early returns, reduced nesting
  2. For Loop Patterns - Range, traditional, infinite
  3. Switch Statements - No fallthrough by default
  4. Type Switch - Handling interface types
  5. Defer - Cleanup operations

Functions

  1. Multiple Return Values - Return (result, error)
  2. Named Return Values - For documentation/defer
  3. new vs make - Allocation primitives

Data

  1. Slices - Dynamic sequences
  2. Maps - Key-value storage
  3. Printing - Format verbs (%v, %+v, %#v)
  4. Append - Growing slices

Initialization

  1. Composite Literals - Inline initialization

Methods

  1. Pointer vs Value Receivers - When to use each

Interfaces

  1. Interfaces - Implicit implementation
  2. Type Assertions - Safe conversion
  3. Embedding - Composition over inheritance

Concurrency

  1. Share by Communicating - Channel-based patterns
  2. Goroutines - Lightweight concurrency
  3. Channels - Communication pipes
  4. Select - Multiplexing channels

Errors

  1. Error Handling - Explicit error returns
  2. Panic - Only for unrecoverable errors
  3. Recover - Panic recovery
  4. Error Wrapping - Adding context with %w

Code Smell Detection Checklist

Critical Anti-Patterns

  • Code not formatted with gofmt
  • Exported names starting with lowercase
  • Panic used in library code
  • Data races (concurrent map access, shared state)
  • Goroutine leaks (no way to stop)
  • Sending on closed channel

High Priority Anti-Patterns

  • Mixed pointer and value receivers on same type
  • Missing error checks
  • Errors ignored with _
  • Improper channel closing (receiver closes, or closing nil channel)
  • Loop variable captured in goroutine (pre-Go 1.22 only — check go.mod)
  • Using new() for slices, maps, channels
  • Not assigning append() result

Medium Priority Anti-Patterns

  • Snake_case naming instead of MixedCaps
  • Large interfaces (>5 methods)
  • Missing doc comments on exported identifiers
  • Using interface{} when specific type would work
  • Not using defer for cleanup
  • Naked returns in long functions
  • Arrays when slices would be better

Low Priority Anti-Patterns

  • Inconsistent naming
  • Missing String() method for custom types
  • Could use type switch instead of repeated assertions
  • Could use composite literal instead of new()

Output Format

1. Anti-Pattern Identified

File: internal/service/order.go:45-78
Smell: Missing error check - result of operation ignored
Principle Violated: Error Handling
Impact: Silent failures, bugs go unnoticed

2. Effective Go Principle to Apply

Principle: Error Handling (from effective-go-principles.json)
Category: Errors
Key Point: Always check errors explicitly, never ignore them
When to Apply: Every function call that returns an error

3. Refactoring Steps

Step 1: Find all places where errors are returned
Step 2: Add explicit error checks with if err != nil
Step 3: Add context to errors with fmt.Errorf("operation failed: %w", err)
Step 4: Propagate or handle errors appropriately
Step 5: Use _ only for intentional ignoring (document why)

4. Code Example

// BEFORE: Missing error check (Anti-pattern)
func processOrder(id string) *Order {
	order, _ := db.GetOrder(id) // ERROR: Ignoring error!
	return order
}

func updateUser(user *User) {
	db.Save(user) // ERROR: Not checking error!
}

// AFTER: Proper error handling (Go idiom)
func processOrder(id string) (*Order, error) {
	order, err := db.GetOrder(id)
	if err != nil {
		return nil, fmt.Errorf("getting order %s: %w", id, err)
	}
	return order, nil
}

func updateUser(user *User) error {
	if err := db.Save(user); err != nil {
		return fmt.Errorf("saving user %s: %w", user.ID, err)
	}
	return nil
}

5. Impact Assessment

Benefits:

  • Errors are caught and handled explicitly
  • Better error context for debugging
  • No silent failures
  • Follows Go conventions

Metrics:

  • Improved reliability
  • Better error messages
  • Easier debugging
  • Code passes go vet checks

Language-Specific Patterns

Error Handling

// Good: Proper error handling with context
func loadConfig(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("reading config from %s: %w", path, err)
	}

	var cfg Config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parsing config: %w", err)
	}

	return &cfg, nil
}

// Usage
cfg, err := loadConfig("config.json")
if err != nil {
	log.Fatalf("Failed to load config: %v", err)
}

Receiver Types

// Good: Consistent pointer receivers
type Counter struct {
	mu    sync.Mutex
	value int
}

// Pointer receiver - modifies state
func (c *Counter) Increment() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.value++
}

// Pointer receiver - consistency
func (c *Counter) Value() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.value
}

// Bad: Mixed receivers
type BadCounter struct {
	value int
}

func (c BadCounter) Increment() { // Value receiver - doesn't modify!
	c.value++ // Modifies copy
}

func (c *BadCounter) Value() int { // Pointer receiver - inconsistent
	return c.value
}

Goroutines and Channels

// Good: Proper goroutine coordination
func processBatch(items []Item) error {
	var wg sync.WaitGroup
	errors := make(chan error, len(items))

	for _, item := range items {
		wg.Add(1)
		item := item // Capture variable (required pre-Go 1.22; unnecessary in 1.22+)

		go func() {
			defer wg.Done()
			if err := process(item); err != nil {
				errors <- err
			}
		}()
	}

	// Wait in separate goroutine
	go func() {
		wg.Wait()
		close(errors) // Sender closes channel
	}()

	// Collect errors
	for err := range errors {
		return err // Return first error
	}

	return nil
}

// Bad: Goroutine leak
func badProcess(items []Item) {
	for _, item := range items {
		go func() {
			process(item) // Captures loop variable - BUG!
			// No coordination, no error handling, no way to stop
		}()
	}
	// Function returns immediately, goroutines may still be running
}

Interfaces

// Good: Small, focused interfaces
type Reader interface {
	Read(p []byte) (n int, err error)
}

type Closer interface {
	Close() error
}

type ReadCloser interface {
	Reader
	Closer
}

// Define where used, not where implemented
type DataStore interface {
	Save(data []byte) error
}

func SaveToStore(store DataStore, data []byte) error {
	return store.Save(data)
}

// Bad: Large, unfocused interface
type Database interface {
	GetUser(id string) (*User, error)
	CreateUser(u *User) error
	UpdateUser(u *User) error
	DeleteUser(id string) error
	GetOrder(id string) (*Order, error)
	CreateOrder(o *Order) error
	// ... 20+ more methods
}

Best Practices

Do

  • Always run gofmt before committing
  • Check all errors explicitly
  • Use defer for cleanup operations
  • Keep interfaces small
  • Accept interfaces, return structs
  • Use pointer receivers for large structs or when modifying
  • Close channels from the sender side
  • Use context for cancellation and timeouts
  • Wrap errors with %w for error chains
  • Use sync.WaitGroup to coordinate goroutines

Don't

  • Don't ignore gofmt warnings
  • Don't use panic in library code
  • Don't ignore errors with _
  • Don't mix pointer and value receivers
  • Don't capture loop variables in goroutines without copying
  • Don't send on closed channels
  • Don't use naked returns in long functions
  • Don't create large interfaces
  • Don't share memory without synchronization
  • Don't use new() for slices, maps, or channels

Resources

Workflow Integration

This skill can be:

  • Invoked from /go-review command
  • Used by go-analyzer agent for autonomous analysis
  • Triggered by pre-commit hooks to check for anti-patterns
  • Called from other skills for Go code improvements

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.