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:
- Identify scope (package, module, or entire project)
- Check Go version and module structure
- Analyze existing code patterns
- 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:
Formatting and Style
- Run gofmt/goimports on all files
- Fix semicolon issues
- Ensure proper brace placement
- Clean up whitespace
Naming Conventions
- Fix package names (lowercase, single-word)
- Correct exported/unexported names
- Apply MixedCaps/mixedCaps consistently
- Rename interfaces (-er suffix for single-method)
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:
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
- gofmt - Standard formatting, non-negotiable
- Semicolons - Automatic insertion, placement rules
Naming
- Package Names - Short, lowercase, single-word
- Exported Names - Uppercase = public
- Interface Naming - -er suffix for single-method
- MixedCaps - No underscores in identifiers
Control Structures
- Guard Clauses - Early returns, reduced nesting
- For Loop Patterns - Range, traditional, infinite
- Switch Statements - No fallthrough by default
- Type Switch - Handling interface types
- Defer - Cleanup operations
Functions
- Multiple Return Values - Return (result, error)
- Named Return Values - For documentation/defer
- new vs make - Allocation primitives
Data
- Slices - Dynamic sequences
- Maps - Key-value storage
- Printing - Format verbs (%v, %+v, %#v)
- Append - Growing slices
Initialization
- Composite Literals - Inline initialization
Methods
- Pointer vs Value Receivers - When to use each
Interfaces
- Interfaces - Implicit implementation
- Type Assertions - Safe conversion
- Embedding - Composition over inheritance
Concurrency
- Share by Communicating - Channel-based patterns
- Goroutines - Lightweight concurrency
- Channels - Communication pipes
- Select - Multiplexing channels
Errors
- Error Handling - Explicit error returns
- Panic - Only for unrecoverable errors
- Recover - Panic recovery
- Error Wrapping - Adding context with %w
Code Smell Detection Checklist
Critical Anti-Patterns
High Priority Anti-Patterns
Medium Priority Anti-Patterns
Low Priority Anti-Patterns
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
1---2name: effective-go3description: 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.4---56# Effective Go Skill78Comprehensive Go refactoring framework based on the official Effective Go guide and Go best practices.910## Prerequisites1112Always read `resources/effective-go-principles.json` (in this skill's directory) before starting.1314It contains 25+ principles with definitions, code smells, and refactoring guidance including:15- Formatting (gofmt, semicolons)16- Naming (packages, interfaces, exported names)17- Control structures (if, for, switch, defer)18- Data structures (slices, maps, arrays)19- Functions (multiple returns, named returns, defer)20- Concurrency (goroutines, channels, select)21- Error handling (error vs panic, wrapping)22- Interfaces and methods (receivers, embedding)2324## Refactoring Approach2526### Four-Phase Strategy2728#### Phase 1: Discovery & Analysis (15-20 min)2930**Understand the Codebase:**311. Identify scope (package, module, or entire project)322. Check Go version and module structure333. Analyze existing code patterns344. Review dependencies and imports3536**Scan for Code Smells:**37- No gofmt/goimports formatting38- Non-idiomatic naming (snake_case, wrong capitalization)39- Wrong receiver types (value when pointer needed)40- Missing error checks41- Goroutine leaks or race conditions42- Improper channel usage43- Panic in library code44- Mutable value types that should be immutable45- Large interfaces (>3 methods for non-standard libs)46- Primitive obsession (no custom types)4748**Technical Exploration** — search and run:49- Run `gofmt -l . | grep -v "vendor/"` — check formatting50- Pattern `^func [a-z]` in `*.go` files — find unexported funcs that may need export51- Pattern `^type [a-z]` — find unexported types52- Pattern `go func` in `*.go` files — find goroutine launches53- Pattern `err :=` — find error assignments54- Pattern `panic\(` — find panic usage in library code55- Pattern `type.*interface` — find interface definitions5657#### Phase 2: Strategic Refactoring Plan (10-15 min)5859Based on loaded Effective Go principles:60611. **Formatting and Style**62 - Run gofmt/goimports on all files63 - Fix semicolon issues64 - Ensure proper brace placement65 - Clean up whitespace66672. **Naming Conventions**68 - Fix package names (lowercase, single-word)69 - Correct exported/unexported names70 - Apply MixedCaps/mixedCaps consistently71 - Rename interfaces (-er suffix for single-method)72733. **Prioritize Refactoring**74 - **Critical**: gofmt, data races, goroutine leaks, missing error checks75 - **High**: Wrong receivers, panic in libraries, improper channel usage76 - **Medium**: Non-idiomatic naming, primitive obsession, large interfaces77 - **Low**: Style improvements, comment formatting7879#### Phase 3: Tactical Pattern Application (30-45 min)8081Apply patterns systematically:8283**1. Formatting**84- Run gofmt -w on all Go files85- Ensure tabs for indentation86- Fix opening brace placement87- Remove unnecessary semicolons8889**2. Naming**90- Package names: short, lowercase, no underscores91- Exported names: Start with uppercase92- Unexported names: Start with lowercase93- Interfaces: Use -er suffix (Reader, Writer, Closer)94- No snake_case: Use MixedCaps or mixedCaps95- Acronyms: All caps (HTTP, URL, ID)9697**3. Control Structures**98- Use guard clauses (early returns)99- Prefer for range over traditional for loops100- Use expression-less switch for if-else chains101- Apply defer for cleanup operations102- Avoid naked returns in long functions103104**4. Error Handling**105- Check all errors explicitly106- Add context with fmt.Errorf and %w107- Return errors, don't panic (except in truly exceptional cases)108- Use errors.Is and errors.As for error checking109- Implement error wrapping consistently110111**5. Concurrency**112- Fix goroutine leaks (ensure they can exit)113- Use channels for communication114- Apply proper channel closing (sender closes)115- Use select for multiplexing116- Avoid shared memory, prefer channels117- Add sync.WaitGroup for coordination118- Fix loop variable capture in goroutines (only an issue pre-Go 1.22; check go.mod)119120**6. Pointers vs Values**121- Use pointer receivers when modifying receiver122- Use pointer receivers for large structs123- Be consistent (all pointer or all value for a type)124- Use pointer receivers for types with sync.Mutex125126**7. Interfaces**127- Keep interfaces small (1-3 methods ideal)128- Define interfaces where used, not where implemented129- Accept interfaces, return structs130- Use empty interface sparingly131132**8. Data Structures**133- Prefer slices over arrays134- Use make() with capacity hints135- Ensure maps are initialized with make()136- Use composite literals for initialization137- Apply append() correctly (assign result)138139#### Phase 4: Validation & Testing (10-15 min)140141**Verify Improvements:**142- [ ] All files pass gofmt check143- [ ] No exported names start with lowercase144- [ ] All errors are checked or explicitly ignored145- [ ] No goroutine leaks detected146- [ ] Channels properly closed from sender147- [ ] Receiver types are consistent and appropriate148- [ ] No panic calls in library code149- [ ] Interfaces are small and focused150- [ ] Code follows Go idioms151152**Testing Strategy:**153- Run go vet on all packages154- Run golint or staticcheck155- Run go test -race to detect data races156- Use go test -cover for coverage157- Run golangci-lint for comprehensive checks158159## Core Effective Go Principles Reference160161### Formatting1621. **gofmt** - Standard formatting, non-negotiable1632. **Semicolons** - Automatic insertion, placement rules164165### Naming1663. **Package Names** - Short, lowercase, single-word1674. **Exported Names** - Uppercase = public1685. **Interface Naming** - -er suffix for single-method1696. **MixedCaps** - No underscores in identifiers170171### Control Structures1727. **Guard Clauses** - Early returns, reduced nesting1738. **For Loop Patterns** - Range, traditional, infinite1749. **Switch Statements** - No fallthrough by default17510. **Type Switch** - Handling interface types17611. **Defer** - Cleanup operations177178### Functions17912. **Multiple Return Values** - Return (result, error)18013. **Named Return Values** - For documentation/defer18114. **new vs make** - Allocation primitives182183### Data18415. **Slices** - Dynamic sequences18516. **Maps** - Key-value storage18617. **Printing** - Format verbs (%v, %+v, %#v)18718. **Append** - Growing slices188189### Initialization19019. **Composite Literals** - Inline initialization191192### Methods19320. **Pointer vs Value Receivers** - When to use each194195### Interfaces19621. **Interfaces** - Implicit implementation19722. **Type Assertions** - Safe conversion19823. **Embedding** - Composition over inheritance199200### Concurrency20124. **Share by Communicating** - Channel-based patterns20225. **Goroutines** - Lightweight concurrency20326. **Channels** - Communication pipes20427. **Select** - Multiplexing channels205206### Errors20728. **Error Handling** - Explicit error returns20829. **Panic** - Only for unrecoverable errors20930. **Recover** - Panic recovery21031. **Error Wrapping** - Adding context with %w211212## Code Smell Detection Checklist213214### Critical Anti-Patterns215- [ ] Code not formatted with gofmt216- [ ] Exported names starting with lowercase217- [ ] Panic used in library code218- [ ] Data races (concurrent map access, shared state)219- [ ] Goroutine leaks (no way to stop)220- [ ] Sending on closed channel221222### High Priority Anti-Patterns223- [ ] Mixed pointer and value receivers on same type224- [ ] Missing error checks225- [ ] Errors ignored with _226- [ ] Improper channel closing (receiver closes, or closing nil channel)227- [ ] Loop variable captured in goroutine (pre-Go 1.22 only — check go.mod)228- [ ] Using new() for slices, maps, channels229- [ ] Not assigning append() result230231### Medium Priority Anti-Patterns232- [ ] Snake_case naming instead of MixedCaps233- [ ] Large interfaces (>5 methods)234- [ ] Missing doc comments on exported identifiers235- [ ] Using interface{} when specific type would work236- [ ] Not using defer for cleanup237- [ ] Naked returns in long functions238- [ ] Arrays when slices would be better239240### Low Priority Anti-Patterns241- [ ] Inconsistent naming242- [ ] Missing String() method for custom types243- [ ] Could use type switch instead of repeated assertions244- [ ] Could use composite literal instead of new()245246## Output Format247248### 1. Anti-Pattern Identified249```250File: internal/service/order.go:45-78251Smell: Missing error check - result of operation ignored252Principle Violated: Error Handling253Impact: Silent failures, bugs go unnoticed254```255256### 2. Effective Go Principle to Apply257```258Principle: Error Handling (from effective-go-principles.json)259Category: Errors260Key Point: Always check errors explicitly, never ignore them261When to Apply: Every function call that returns an error262```263264### 3. Refactoring Steps265```266Step 1: Find all places where errors are returned267Step 2: Add explicit error checks with if err != nil268Step 3: Add context to errors with fmt.Errorf("operation failed: %w", err)269Step 4: Propagate or handle errors appropriately270Step 5: Use _ only for intentional ignoring (document why)271```272273### 4. Code Example274```go275// BEFORE: Missing error check (Anti-pattern)276func processOrder(id string) *Order {277 order, _ := db.GetOrder(id) // ERROR: Ignoring error!278 return order279}280281func updateUser(user *User) {282 db.Save(user) // ERROR: Not checking error!283}284285// AFTER: Proper error handling (Go idiom)286func processOrder(id string) (*Order, error) {287 order, err := db.GetOrder(id)288 if err != nil {289 return nil, fmt.Errorf("getting order %s: %w", id, err)290 }291 return order, nil292}293294func updateUser(user *User) error {295 if err := db.Save(user); err != nil {296 return fmt.Errorf("saving user %s: %w", user.ID, err)297 }298 return nil299}300```301302### 5. Impact Assessment303**Benefits:**304- Errors are caught and handled explicitly305- Better error context for debugging306- No silent failures307- Follows Go conventions308309**Metrics:**310- Improved reliability311- Better error messages312- Easier debugging313- Code passes go vet checks314315## Language-Specific Patterns316317### Error Handling318```go319// Good: Proper error handling with context320func loadConfig(path string) (*Config, error) {321 data, err := os.ReadFile(path)322 if err != nil {323 return nil, fmt.Errorf("reading config from %s: %w", path, err)324 }325326 var cfg Config327 if err := json.Unmarshal(data, &cfg); err != nil {328 return nil, fmt.Errorf("parsing config: %w", err)329 }330331 return &cfg, nil332}333334// Usage335cfg, err := loadConfig("config.json")336if err != nil {337 log.Fatalf("Failed to load config: %v", err)338}339```340341### Receiver Types342```go343// Good: Consistent pointer receivers344type Counter struct {345 mu sync.Mutex346 value int347}348349// Pointer receiver - modifies state350func (c *Counter) Increment() {351 c.mu.Lock()352 defer c.mu.Unlock()353 c.value++354}355356// Pointer receiver - consistency357func (c *Counter) Value() int {358 c.mu.Lock()359 defer c.mu.Unlock()360 return c.value361}362363// Bad: Mixed receivers364type BadCounter struct {365 value int366}367368func (c BadCounter) Increment() { // Value receiver - doesn't modify!369 c.value++ // Modifies copy370}371372func (c *BadCounter) Value() int { // Pointer receiver - inconsistent373 return c.value374}375```376377### Goroutines and Channels378```go379// Good: Proper goroutine coordination380func processBatch(items []Item) error {381 var wg sync.WaitGroup382 errors := make(chan error, len(items))383384 for _, item := range items {385 wg.Add(1)386 item := item // Capture variable (required pre-Go 1.22; unnecessary in 1.22+)387388 go func() {389 defer wg.Done()390 if err := process(item); err != nil {391 errors <- err392 }393 }()394 }395396 // Wait in separate goroutine397 go func() {398 wg.Wait()399 close(errors) // Sender closes channel400 }()401402 // Collect errors403 for err := range errors {404 return err // Return first error405 }406407 return nil408}409410// Bad: Goroutine leak411func badProcess(items []Item) {412 for _, item := range items {413 go func() {414 process(item) // Captures loop variable - BUG!415 // No coordination, no error handling, no way to stop416 }()417 }418 // Function returns immediately, goroutines may still be running419}420```421422### Interfaces423```go424// Good: Small, focused interfaces425type Reader interface {426 Read(p []byte) (n int, err error)427}428429type Closer interface {430 Close() error431}432433type ReadCloser interface {434 Reader435 Closer436}437438// Define where used, not where implemented439type DataStore interface {440 Save(data []byte) error441}442443func SaveToStore(store DataStore, data []byte) error {444 return store.Save(data)445}446447// Bad: Large, unfocused interface448type Database interface {449 GetUser(id string) (*User, error)450 CreateUser(u *User) error451 UpdateUser(u *User) error452 DeleteUser(id string) error453 GetOrder(id string) (*Order, error)454 CreateOrder(o *Order) error455 // ... 20+ more methods456}457```458459## Best Practices460461### Do462- Always run gofmt before committing463- Check all errors explicitly464- Use defer for cleanup operations465- Keep interfaces small466- Accept interfaces, return structs467- Use pointer receivers for large structs or when modifying468- Close channels from the sender side469- Use context for cancellation and timeouts470- Wrap errors with %w for error chains471- Use sync.WaitGroup to coordinate goroutines472473### Don't474- Don't ignore gofmt warnings475- Don't use panic in library code476- Don't ignore errors with _477- Don't mix pointer and value receivers478- Don't capture loop variables in goroutines without copying479- Don't send on closed channels480- Don't use naked returns in long functions481- Don't create large interfaces482- Don't share memory without synchronization483- Don't use new() for slices, maps, or channels484485## Resources486487- **Effective Go Principles**: See `resources/effective-go-principles.json` for complete definitions488- **Checklist**: See `CHECKLIST.md` for full anti-pattern list489- **Official Guide**: https://go.dev/doc/effective_go490- **Go Code Review Comments**: https://go.dev/wiki/CodeReviewComments491492## Workflow Integration493494This skill can be:495- Invoked from `/go-review` command496- Used by `go-analyzer` agent for autonomous analysis497- Triggered by pre-commit hooks to check for anti-patterns498- Called from other skills for Go code improvements