Write idiomatic Go code following community standards, Effective Go principles, and Google's style guide. Covers naming, error handling, concurrency, testing, and project structure.
Write simple, clear, and idiomatic Go code following [Effective Go](https://go.dev/doc/effective_go), [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments), and [Google's Go Style Guide](https://google.github.io/styleguide/go/).
Follow these fundamental principles when writing Go code:
1. Use lowercase, single-word names without underscores, hyphens, or mixedCaps
2. Choose names describing what the package provides, not what it contains
3. Avoid generic names like `util`, `common`, or `base`
4. Use singular forms, not plural (e.g., `user` not `users`)
1. Use mixedCaps or MixedCaps (camelCase) rather than underscores
2. Keep names short but descriptive
3. Use single-letter variables only for very short scopes (loop indices)
4. Start exported names with capital letters
5. Start unexported names with lowercase letters
6. Avoid stuttering (e.g., `http.Server` not `http.HTTPServer`)
1. Name single-method interfaces with `-er` suffix (e.g., `Reader`, `Writer`, `Formatter`)
2. Name interface after the method for single-method interfaces (e.g., `Read` → `Reader`)
3. Keep interfaces small and focused (1-3 methods ideal)
1. Use MixedCaps for exported constants
2. Use mixedCaps for unexported constants
3. Group related constants using `const` blocks
4. Use typed constants for better type safety
1. Always run `gofmt` to format code before committing
2. Use `goimports` to automatically manage imports
3. Keep line length reasonable (no hard limit, prioritize readability)
4. Add blank lines to separate logical groups of code
1. Write comments in complete sentences
2. Start sentences with the name of the thing being described
3. Begin package comments with "Package [name]..."
4. Use line comments (`//`) for most documentation
5. Reserve block comments (`/* */`) for package documentation
6. Document why, not what (unless the what is complex)
1. Check errors immediately after function calls
2. Never ignore errors with `_` without documenting why
3. Wrap errors with context using `fmt.Errorf` with `%w` verb
4. Create custom error types for specific error checking needs
5. Always place error returns as the last return value
6. Name error variables `err`
7. Keep error messages lowercase without ending punctuation
Example:
```go
// Good
if err := doSomething(); err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
// Bad - ignoring error
_ = doSomething()
```
1. Follow standard Go project layout conventions
2. Place `main` packages in `cmd/` directory
3. Put reusable packages in `pkg/` or `internal/`
4. Use `internal/` for packages that shouldn't be imported externally
5. Group related functionality into cohesive packages
6. Avoid circular dependencies
1. Use Go modules (`go.mod` and `go.sum`)
2. Keep dependencies minimal
3. Regularly update dependencies for security patches
4. Run `go mod tidy` to remove unused dependencies
5. Vendor dependencies only when necessary
1. Define custom types to add meaning and type safety
2. Use struct tags for JSON, XML, and database mappings
3. Prefer explicit type conversions
4. Check the second return value when using type assertions
1. Use pointers for large structs or when you need to modify the receiver
2. Use values for small structs and when immutability is desired
3. Be consistent within a type's method set
4. Consider the zero value when choosing pointer vs value receivers
1. Accept interfaces, return concrete types
2. Keep interfaces small (1-3 methods is ideal)
3. Use embedding for composition
4. Define interfaces close to where they're used, not where they're implemented
5. Don't export interfaces unless necessary
1. Never create goroutines in libraries; let the caller control concurrency
2. Always know how a goroutine will exit
3. Use `sync.WaitGroup` or channels to wait for goroutines to complete
4. Avoid goroutine leaks by ensuring proper cleanup
5. Pass context for cancellation and timeout handling
1. Use channels to communicate between goroutines
2. Follow "don't communicate by sharing memory; share memory by communicating"
3. Close channels from the sender side only, not the receiver
4. Use buffered channels when you know the required capacity
5. Use `select` for non-blocking operations and multiplexing
1. Use `sync.Mutex` for protecting shared state
2. Keep critical sections as small as possible
3. Use `sync.RWMutex` when you have many readers and few writers
4. Prefer channels over mutexes when appropriate
5. Use `sync.Once` for one-time initialization
1. Keep tests in the same package for white-box testing
2. Use `_test` package suffix for black-box testing
3. Name test files with `_test.go` suffix
4. Place test files next to the code they test
1. Use table-driven tests for multiple test cases
2. Name tests descriptively: `Test_functionName_scenario`
3. Use subtests with `t.Run` for better organization and parallel execution
4. Test both success and error cases
5. Mark helper functions with `t.Helper()`
6. Clean up resources using `t.Cleanup()` or `defer`
Example:
```go
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -2, -3, -5},
{"mixed signs", 2, -3, -1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
```
1. Validate all external input at system boundaries
2. Use strong typing to prevent invalid states
3. Use parameterized queries to prevent SQL injection
4. Validate file paths from user input
5. Sanitize and escape data for different contexts (HTML, SQL, shell)
1. Use standard library `crypto` packages
2. Never implement your own cryptographic algorithms
3. Use `crypto/rand` for cryptographic random number generation
4. Hash passwords using `bcrypt` or `argon2`
5. Always use TLS for network communication
1. Minimize allocations in hot code paths
2. Reuse objects when appropriate (consider `sync.Pool`)
3. Use value receivers for small structs
4. Preallocate slices when size is known: `make([]T, 0, capacity)`
5. Avoid unnecessary string conversions and concatenations
1. Use built-in profiling tools (`pprof`) before optimizing
2. Write benchmarks for critical code paths using `testing.B`
3. Profile before optimizing (don't guess)
4. Focus on algorithmic improvements first
5. Optimize only after measuring performance impact
1. Not checking errors
2. Ignoring race conditions (use `go test -race`)
3. Creating goroutine leaks
4. Not using `defer` for cleanup (files, locks, connections)
5. Modifying maps concurrently without synchronization
6. Confusing nil interfaces with nil pointers
7. Using global variables unnecessarily
8. Over-using empty interfaces (`interface{}` or `any`)
9. Not considering the zero value of types
10. Deferring functions in loops without understanding the implications
Run these tools regularly as part of your development workflow:
1. `go fmt` - Format code automatically
2. `go vet` - Find suspicious constructs
3. `golangci-lint` - Comprehensive linting
4. `go test -race` - Detect race conditions
5. `go mod tidy` - Clean up dependencies
6. `go generate` - Run code generation tools
1. Document all exported symbols (types, functions, methods, constants, variables)
2. Start documentation comments with the symbol name
3. Include usage examples in documentation when helpful
4. Keep documentation close to code
5. Update documentation when code changes
6. Write package-level documentation in a `doc.go` file for complex packages
Example:
```go
// Package http provides HTTP client and server implementations.
package http
// Client is an HTTP client for making requests.
// Its zero value is a usable client that uses DefaultTransport.
type Client struct {
// ...
}
// Get issues a GET request to the specified URL.
// It returns an error if the request fails or the response status is not 2xx.
func (c *Client) Get(url string) (*Response, error) {
// ...
}
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/go-development-best-practices/raw