Golang Style Guide¶
What's on this page
- Core content for this topic in the Inkorporated enterprise OS.
- Practical guidance, roles, or standards as applicable.
What this enables
- Consistent enterprise operations and decision-making.
- Shared language for humans and cyborg AI agents.
This document outlines the coding standards and best practices for Go (Golang) development within this project. Adhering to these guidelines ensures code consistency, readability, and maintainability.
Table of Contents¶
- General Principles
- Formatting
- Naming Conventions
- Project Layout
- Documentation and Comments
- Error Handling
- Concurrency
- Interfaces
- Testing
- Dependencies
- Performance and Optimization
- Linting and Tooling
- Common Mistakes and Gotchas
General Principles¶
- Simplicity: Go is designed to be simple. Avoid over-engineering.
- Readability: Clear code is better than clever code.
- Orthogonality: Keep concepts independent.
- Idiomatic Go: Follow established conventions (e.g., Effective Go, Go Code Review Comments).
- Explicit Dependencies: Avoid magic or implicit behavior.
Formatting¶
- gofmt: All code must be formatted with
gofmt(orgoimports). This is non-negotiable. - Line Length: Go has no strict line length limit, but avoid excessively long lines. Break long lines logically.
- Imports:
- Group imports into standard library, third-party, and local packages.
- Use
goimportsto manage imports automatically.
Naming Conventions¶
- Casing: Use
MixedCapsorCamelCase. Go does not use underscores in names (except in_test.gofiles or build tags).- Public (Exported): Starts with an uppercase letter (e.g.,
ServeHTTP). - Private (Unexported): Starts with a lowercase letter (e.g.,
parseRequest).
- Public (Exported): Starts with an uppercase letter (e.g.,
- Package Names: Short, concise, and lowercase. Avoid
util,common, orhelpers. - Interfaces:
- Single method interfaces should end in
-er(e.g.,Reader,Writer).
- Single method interfaces should end in
- Variables:
- Short names for local variables with limited scope (e.g.,
ifor loop index,rfor reader). - More descriptive names for larger scopes.
- Short names for local variables with limited scope (e.g.,
- Getters: Do not use
Getprefix.- Field:
owner - Getter:
Owner()(notGetOwner) - Setter:
SetOwner()
- Field:
- Acronyms: Keep acronyms consistently uppercased or lowercased.
- Good:
ServeHTTP,IDProcessor - Bad:
ServeHttp,IdProcessor
- Good:
Project Layout¶
- Standard Layout: Follow the Standard Go Project Layout where applicable.
/cmd: Main applications./pkg: Library code that's ok to use by external applications./internal: Private application and library code./api: OpenAPI/Swagger specs, JSON schema files, protocol definition files.
- Grouping: Group code by functionality (domain), not by type (e.g., avoid
models,controllerspackages unless warranted by specific framework patterns).
Documentation and Comments¶
- Godoc: All exported types, variables, constants, and functions must have comments.
- Comments should start with the name of the thing being described.
- Example:
// Request represent an incoming HTTP request.
- Package Comments: Every package should have a package comment in one of its files.
// Package json implements encoding and decoding of JSON ...
- Notes: Use
// TODO(User):or// FIXME:to mark areas needing attention.
Error Handling¶
- Check Errors: Always check errors. Never ignore them using
_. - Handling: Handle errors once. Wrap them to add context, or return them, or log them (at the top level).
- Wrapping: Use
%wwithfmt.Errorfto wrap errors forerrors.Isanderrors.Assupport. - Custom Errors: Define custom error types or sentinel errors for specific conditions.
- Panic: Avoid
panicin library code. Only use it for unrecoverable errors during initialization or logical inconsistencies that should be caught by tests.
Concurrency¶
- Goroutines: Start goroutines only when you know how they will stop. Avoid leaking goroutines.
- Channels: Use channels for orchestration and signaling.
- Mutexes: Use
sync.Mutexorsync.RWMutexfor protecting shared state. - Context: Use
context.Contextfor cancellation, timeouts, and passing request-scoped values.- Pass
ctxas the first argument to functions. - Never store contexts in structs (except maybe for testing).
- Pass
- WaitGroups: Use
sync.WaitGroupto wait for a collection of goroutines to finish.
Interfaces¶
- Consumer Defined: Interfaces should be defined where they are used (consumer side), not where they are implemented (producer side).
- Small Interfaces: Prefer small interfaces (often single method) over large ones.
- Accept Interfaces, Return Structs: Functions should generally accept interfaces and return concrete types.
Testing¶
- Package: Use the standard
testingpackage. - Naming: Test files must end with
_test.go. Test functions must start withTest. - Table-Driven Tests: Use table-driven tests for covering multiple scenarios efficiently.
- Subtests: Use
t.Runfor logical grouping and running specific tests. - Benchmarks: Use
Benchmarkfunctions to measure performance. - Examples: Use
Examplefunctions for documentation and verification. - Test Main: Use
TestMainonly for global setup/teardown if absolutely necessary.
Dependencies¶
- Go Modules: Use Go Modules (
go.mod,go.sum) for dependency management. - Tidiness: Run
go mod tidyregularly to keep dependencies clean. - Vendoring: Vendor dependencies (
go mod vendor) if the project requires reproducible builds without relying on external proxies (optional).
Performance and Optimization¶
- Preallocation: Preallocate slices and maps if the size is known.
- Pointers: Use pointers for large structs to avoid copying, but be aware of escape analysis and garbage collection pressure.
- Defer:
deferhas a small overhead. Avoid it in tight loops if performance is critical.
Linting and Tooling¶
- Linter: Use
golangci-lintwith a robust configuration.- Enabled linters:
govet,staticcheck,errcheck,ineffassign,gocyclo,gocritic,revive.
- Enabled linters:
- Editor Integration: Use
gopls(Go Language Server) for autocomplete, formatting, and refactoring.
Common Mistakes and Gotchas¶
- Loop Variables: Be careful capturing loop variables in closures (fixed in Go 1.22+).
- Nil Interfaces: A nil interface is not the same as an interface containing a nil pointer.
- Slice Memory Leaks: Reslicing a large array/slice can keep the underlying array in memory. Copy explicitly if needed.
Related Interview Questions¶
- Practice Questions: Test your knowledge of Golang concepts.