chad/effective-go icon
public
Published on 3/14/2025
Effective Go

I asked Claude to distill https://go.dev/doc/effective_go into a rules file.

Rules
effective-go
## Formatting
- Always format Go code according to standard Go conventions. Use tabs for indentation, not spaces. Don't worry about line length, but use an extra tab for wrapped lines. Minimize parentheses in control structures.
- Prefer line comments (// ...) for normal code comments. Use block comments (/* */) primarily for package documentation or to temporarily disable large code sections.

## Naming
- Use short, concise, lowercase, single-word names without underscores or mixedCaps for packages.
- Name single-method interfaces by the method name plus an 'er' suffix (Reader, Writer, etc.).
- Use MixedCaps (PascalCase for exported, camelCase for unexported) rather than underscores to write multiword names.
- For a field named 'owner', name the getter simply 'Owner()' (not 'GetOwner()'). A setter should be named 'SetOwner()'.

## Control Structures
- Omit unnecessary else blocks after returns. When an if statement ends with a terminal statement (return, break, etc.), eliminate the else.
- Use appropriate for loop forms: 'for init; condition; post {}', 'for condition {}' (while), 'for {}' (infinite), or 'for key, value := range collection {}'.
- Use Go's flexible switch statements. Cases can be comma-separated lists. Use switch without an expression as an alternative to if-else chains.

## Functions and Methods
- Use multiple return values, typically with the error as the last return value: 'func Name() (result, err error)'.
- Use named return parameters when they clarify which returned value is which.
- Use defer statements for cleanup operations, placing them near the resource acquisitions they clean up.
- Use pointer receivers when the method needs to modify the receiver or when the receiver is large.

## Data Structures
- Use 'new(T)' to allocate zeroed memory for a type. Use 'make(T, args)' only for slices, maps, and channels.
- Prefer slices over arrays in most cases for sequences of data.
- Use the comma-ok idiom with maps to distinguish between missing entries and zero values: 'value, ok := map[key]'.
- Use embedding for composition rather than trying to simulate inheritance.

## Error Handling
- Return error values explicitly as the last return value with descriptive context.
- Check errors immediately and handle them explicitly. Avoid using _ to ignore errors.
- Use panic only for exceptional conditions that indicate programming errors, not for normal error handling.

## Concurrency
- Follow the principle 'Do not communicate by sharing memory; instead, share memory by communicating.'
- Use goroutines for concurrent execution with proper coordination through channels or other synchronization.
- Choose unbuffered channels for synchronization points, buffered channels as semaphores or to limit throughput.

## Interfaces
- Create small, focused interfaces with only the methods necessary, preferably with just one or two methods.
- Accept interfaces as parameters to be more flexible, but return concrete types from functions.
- Focus interfaces on what actions are available rather than how they're implemented.

## General Practices
- Use composite literals for concise initialization of structs, slices, maps, and arrays.
- Use the blank identifier (_) to explicitly ignore unwanted values.
- Use init functions sparingly and only for tasks that cannot be accomplished through variable initialization.