Effective Go Code Reviewer
Reviews Go code against the official Effective Go guide and provides actionable feedback for writing clear, performant, and idiomatic Go code.
What This Skill Does
This skill analyzes Go source code and evaluates it against the principles and conventions documented in the [Effective Go guide](https://go.dev/doc/effective_go). It identifies non-idiomatic patterns, suggests improvements, and helps developers write Go code that follows community best practices.
Instructions
When reviewing Go code, follow these steps systematically:
1. Initial Assessment
Identify all `.go` files in the provided codebase or specific files/directoriesRead the source code thoroughlyNote the overall structure: package organization, imports, types, functions2. Formatting Check
**Run `gofmt` first:**
Execute `gofmt -l .` to identify unformatted filesIf any files are listed, run `gofmt -w .` to fix formatting automaticallyReport which files were reformatted**Check for:**
Proper indentation (tabs, not spaces)Consistent spacing around operatorsAligned struct field commentsLine wrapping for long lines (wrap and indent with extra tab)Minimal use of parentheses in control structures3. Naming Conventions
**Package Names:**
Lower case, single-word names (e.g., `bytes`, `http`, `json`)No underscores or mixedCapsBase name matches source directory nameShort and evocative**Exported Names:**
Use package context to avoid stuttering (e.g., `buf.Reader` not `buf.BufReader`)Constructor functions: `New` or `NewTypeName` depending on package exportsGetters: use `Owner()` not `GetOwner()`Setters: use `SetOwner()` when neededInterface names: method name + `-er` suffix (e.g., `Reader`, `Writer`, `Formatter`)**General:**
Use `MixedCaps` or `mixedCaps`, never underscoresShort variable names in small scopes (`i`, `r`, `w`)Descriptive names for package-level declarations4. Control Structures
**If Statements:**
Use initialization statements when appropriate: `if err := file.Chmod(0664); err != nil`Avoid unnecessary `else` blocks; return early insteadCheck errors immediately after operations**For Loops:**
Use range for slices, maps, channels, stringsPrefer `for range` over manual indexing when index isn't neededUse blank identifier `_` for unused values**Switch Statements:**
Cases don't fall through by default (no `break` needed)Use `fallthrough` explicitly when neededMultiple values in case: `case 0, 1, 2, 3:`Can switch on any type, including `nil`Use type switches for interface type checking5. Functions and Methods
**Multiple Return Values:**
Return error as last valueUse named return values for documentation, not always for implementationAvoid naked returns except in very short functions**Defer, Panic, Recover:**
Use `defer` for cleanup (closing files, unlocking mutexes)Only panic for truly unrecoverable errorsRecover only in deferred functionsDocument functions that may panic**Error Handling:**
Always check errors; don't use `_` to discardReturn errors up the call stack with contextUse `fmt.Errorf` with `%w` for error wrappingDon't log and return errors (choose one)6. Data Structures
**Allocation:**
Use `new` for zero-valued types needing pointerPrefer composite literals: `&File{fd: fd, name: name}`Make slice/map with `make` when size is known**Arrays vs Slices:**
Prefer slices over arrays for most use casesPass slices, not pointers to arraysUse `make([]Type, length, capacity)` for known sizes**Maps:**
Initialize with `make` or composite literalsCheck for existence: `val, ok := map[key]`Delete with `delete(map, key)`Zero value of map is `nil` (cannot insert; must initialize)**Structs:**
Use composite literals with field names for clarityGroup related fields togetherUse embedded types for composition7. Initialization
**Constants:**
Use `const` for true constantsUse `iota` for enumerationsGroup related constants in parenthesized blocks**Variables:**
Use short declarations (`:=`) inside functionsUse `var` at package level or when type differs from initializerZero values are useful (0, false, nil, empty string)**Init Function:**
Use `init()` sparingly for complex initializationRuns after all variable declarations evaluatedCannot be called directly8. Interfaces and Types
**Interface Design:**
Keep interfaces small (1-3 methods ideal)Accept interfaces, return concrete typesDefine interfaces in consumer package, not producerUse standard interface names (`io.Reader`, `io.Writer`, etc.)**Type Assertions:**
Use comma-ok idiom: `value, ok := x.(T)`Use type switches for multiple type checksHandle unexpected types gracefully**Methods:**
Use pointer receivers for mutating methodsUse pointer receivers for large structsBe consistent: if some methods need pointers, use pointers for all9. Concurrency
**Goroutines:**
Launch with `go` keyword: `go function(args)`Document goroutine lifecycle (who starts, who stops)Ensure goroutines can exit to avoid leaksUse WaitGroups or channels to coordinate**Channels:**
Make with `make(chan Type, capacity)`Close only from sender sideUse buffered channels to prevent blocking when appropriateSelect on multiple channels with `select`**Synchronization:**
Prefer channels over shared memory with locksUse `sync.Mutex` when shared memory is necessaryUse `sync.RWMutex` for read-heavy workloadsNever copy a mutex (pass pointer)**Common Patterns:**
Producer-consumer with channelsFan-out, fan-in patternsWorker pools with buffered channelsContext for cancellation and timeouts10. Documentation
**Doc Comments:**
Start with package doc comment before `package` declarationDocument all exported identifiers (types, functions, constants, variables)First sentence should be summary starting with nameUse complete sentences with proper punctuationInclude examples in `_test.go` files using `Example` functions11. Testing
**Test Files:**
Name test files `*_test.go`Use package `package_name_test` for black-box testsTest function names: `TestFunctionName(t *testing.T)`**Best Practices:**
Use table-driven tests for multiple casesUse `t.Helper()` in test helper functionsUse subtests with `t.Run()` for organizationUse `testdata` directory for test fixtures12. Common Anti-Patterns to Flag
Using `panic` for normal error handlingNot checking errorsCopying mutexes (embedding `sync.Mutex` in copied struct)Goroutine leaks (no exit condition)Naked returns in long functionsOveruse of blank identifier `_`Unnecessary `else` after `return`Pointer to interface (almost always wrong)Ignoring zero values (e.g., initializing `var buf bytes.Buffer` to empty)13. Generate Report
Provide a structured review report with:
1. **Summary:** Overall code quality assessment (Good/Fair/Needs Improvement)
2. **Formatting Issues:** List files needing `gofmt`, alignment problems
3. **Naming Issues:** Non-idiomatic names with suggested fixes
4. **Control Structure Issues:** Unnecessary complexity, missing error checks
5. **Concurrency Issues:** Goroutine leaks, race conditions, mutex copying
6. **Documentation Gaps:** Missing doc comments on exported identifiers
7. **Performance Suggestions:** Opportunities for optimization (with benchmarks if needed)
8. **Positive Patterns:** Highlight good idiomatic Go code to reinforce
For each issue:
Show the problematic code snippet with file:line referenceExplain why it's non-idiomaticProvide corrected code exampleReference relevant section of Effective Go guide14. Prioritization
Categorize issues by severity:
**Critical:** Will cause bugs (race conditions, goroutine leaks, unchecked errors)**High:** Violates important conventions (exported names, error handling patterns)**Medium:** Style issues that reduce readability (naming, formatting)**Low:** Minor improvements (doc comments, variable names in small scope)Usage Examples
**Example 1: Review entire project**
```
Review all Go code in this repository following Effective Go guidelines.
```
**Example 2: Review specific file**
```
Review the file src/handlers/user.go for idiomatic Go patterns.
```
**Example 3: Focus on specific area**
```
Review the concurrency patterns in pkg/worker/ for goroutine leaks and race conditions.
```
**Example 4: Before pull request**
```
Perform a comprehensive Effective Go review before I submit this PR.
```
Constraints
This skill focuses on idiomatic style and conventions, not functional correctnessAlways run `gofmt` first before reviewing manuallyDefer to `gofmt` for formatting decisionsSuggest `golint`, `staticcheck`, or `go vet` for additional static analysisReference official Effective Go guide sections in feedbackAvoid opinionated style preferences not covered in Effective GoWhen uncertain, cite standard library examples as referenceReferences
[Effective Go](https://go.dev/doc/effective_go)[Go Language Specification](https://go.dev/ref/spec)[Go Standard Library](https://pkg.go.dev/std)[Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)