Naming Conventions & Idiomatic Style
Go has very few naming rules baked into the compiler, but the community has strong conventions, enforced by tools and code review. Follow them and your code will look like every other Go project. Ignore them and you'll stand out for the wrong reason.
Learning objectives
- Use MixedCase (camelCase/PascalCase), never snake_case.
- Capitalize acronyms correctly (URL, HTTP, ID).
- Choose short, descriptive names for locals and short receiver names for methods.
- Pick idiomatic package and interface names.
- Let
gofmt,go vet, andstaticcheckdo style enforcement for you.
Principles
- Short, not cryptic.
ifor an index in a loop is fine;ifor an invoice object is not. - Scope matters. Shorter names for shorter scopes. A two-line local can be
n; a function argument used throughout should bename. - Consistency beats novelty. If the stdlib calls it
Reader, don't inventIReadable.
Identifier casing
| Kind | Style | Example |
|---|---|---|
| Exported (public) | PascalCase | UserID, ServeHTTP, MaxRetries |
| Unexported | camelCase | userID, serveHTTP, maxRetries |
| Constants | Same as above, just because it's const doesn't make it SHOUTY | MaxRetries, not MAX_RETRIES |
_). You'll see MAX_RETRIES in C, Python, Ruby, never in Go.
Acronyms are all one case
// Right
URL, ID, HTTP, JSON, DB, API, OS
ServeHTTP, ReadJSON, UserID, APIKey, parseURL
// Wrong
Url, Id, Http, Json // mixed within an acronym
This applies to both exported and unexported: userID,
parseURL. The rule: if a word is an acronym, keep it in
one case throughout (all upper for exported, all lower for
unexported-at-start).
Package names
- Lower case, no underscores:
strings,nethttp(notnet_http). - Short and on-topic:
time,io,os: nottimeutil_helpers. - Singular:
util, notutils;store, notstores. - Names appear as
pkg.Nameat call sites, so avoid redundancy:strings.Reader, notstrings.StringReader.
Interface names
Single-method interfaces are named after their method + "er":
type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
type Closer interface { Close() error }
type Stringer interface { String() string }
Multi-method interfaces get a descriptive name: ReadWriter,
http.ResponseWriter. Avoid Hungarian-notation prefixes
(IReader), Go doesn't distinguish interface names from
type names at the call site.
Receiver names (for methods)
Short, consistent across all methods of a type, typically one or two letters:
func (u *User) FullName() string { ... }
func (u *User) Email() string { ... }
// Consistent: always `u` for User
Do NOT use this or self. They're idiomatic in
Java/Python; in Go they look out of place.
Error naming
Error variables start with Err:
var ErrNotFound = errors.New("not found")
var ErrUnauthorized = errors.New("unauthorized")
Error types end with Error:
type ValidationError struct { Field, Reason string }
func (e *ValidationError) Error() string { ... }
Constants
const (
StatusOK = 200 // PascalCase for exported
defaultTimeout = 30 // camelCase for unexported
)
Reserved words
Just 25, which is remarkable, compare to Java's ~50 or Python's ~35:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
Let the tools keep you honest
gofmt: formatting. You already run it on save (Chapter 4). Non-negotiable.go vet: catches common mistakes (misspellings, bad Printf args, unused results, impossible interface assertions). Run in CI.staticcheck: third-party, but the community standard. Finds style issues, anti-patterns, and real bugs that go vet misses.go install honnef.co/go/tools/cmd/staticcheck@latest staticcheck ./...golangci-lint: meta-linter that runs many analyzers at once. Most production projects use it.
Check your understanding
Practice exercises
Rename for style
The following has every naming mistake in the book. Rewrite it in idiomatic Go.
type user_account struct {
User_ID int
User_Email string
CREATED_AT int64
}
func (this *user_account) get_full_email() string {
return this.User_Email
}
const MAX_USER_NAME_LENGTH = 64
var errorNotFound = "not found"
Show solution
type UserAccount struct {
ID int
Email string
CreatedAt int64
}
func (u *UserAccount) FullEmail() string {
return u.Email
}
const MaxUserNameLength = 64
var ErrNotFound = errors.New("not found")
Key changes: no underscores, consistent camelCase/PascalCase, acronym-case (ID), short receiver (u), Err-prefix for error variable, and the error is an actual error value (not a string).
Further reading
- Effective Go: the community-authoritative style guide
- Go Code Review Comments
- Google Go Style Guide
- staticcheck.dev
Style in hand.