What's in a name?
October 2014
Andrew Gerrand
Google Inc.
Andrew Gerrand
Google Inc.
Readability is the defining quality of good code.
Good names are critical to readability.
This talk is about naming in Go.
2A good name is:
The greater the distance between a name's declaration and its uses,
the longer the name should be.
Names in Go should use MixedCase
.
(Don't use names_with_underscores
.)
Acronyms should be all capitals, as in ServeHTTP
and IDProcessor
.
Keep them short; long names obscure what the code does.
Common variable/type combinations may use really short names:
Prefer i
to index
.
Prefer r
to reader
.
Prefer b
to buffer
.
Avoid redundant names, given their context:
Prefer count
to runeCount
inside a function named RuneCount
.
Prefer ok
to keyInMap
in the statement
v, ok := m[k]
Longer names may help in long functions, or functions with many local variables.
(But often this just means you should refactor.)
func RuneCount(buffer []byte) int { runeCount := 0 for index := 0; index < len(buffer); { if buffer[index] < RuneSelf { index++ } else { _, size := DecodeRune(buffer[index:]) index += size } runeCount++ } return runeCount }
func RuneCount(b []byte) int { count := 0 for i := 0; i < len(b); { if b[i] < RuneSelf { i++ } else { _, n := DecodeRune(b[i:]) i += n } count++ } return count }
Function parameters are like local variables,
but they also serve as documentation.
Where the types are descriptive, they should be short:
func AfterFunc(d Duration, f func()) *Timer func Escape(w io.Writer, s []byte)
Where the types are more ambiguous, the names may provide documentation:
func Unix(sec, nsec int64) Time func HasPrefix(s, prefix []byte) bool
Return values on exported functions should only be named for documentation purposes.
These are good examples of named return values:
func Copy(dst Writer, src Reader) (written int64, err error) func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
Receivers are a special kind of argument.
By convention, they are one or two characters that reflect the receiver type,
because they typically appear on almost every line:
func (b *Buffer) Read(p []byte) (n int, err error) func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) func (r Rectangle) Size() Point
Receiver names should be consistent across a type's methods.
(Don't use r
in one method and rdr
in another.)
Exported names are qualified by their package names.
Remember this when naming exported variables, constants, functions, and types.
That's why we have bytes.Buffer
and strings.Reader
,
not bytes.ByteBuffer
and strings.StringReader
.
Interfaces that specify just one method are usually just that function name with 'er' appended to it.
type Reader interface { Read(p []byte) (n int, err error) }
Sometimes the result isn't correct English, but we do it anyway:
type Execer interface { Exec(query string, args []Value) (Result, error) }
Sometimes we use English to make it nicer:
type ByteReader interface { ReadByte() (c byte, err error) }
When an interface includes multiple methods, choose a name that accurately describes its purpose (examples: net.Conn
, http.ResponseWriter
, io.ReadWriter
).
Error types should be of the form FooError
:
type ExitError struct { ... }
Error values should be of the form ErrFoo
:
var ErrFormat = errors.New("image: unknown format")
Choose package names that lend meaning to the names they export.
Steer clear of util
, common
, and the like.
The last component of a package path should be the same as the package name.
"compress/gzip" // package gzip
Avoid stutter in repository and package paths:
"code.google.com/p/goauth2/oauth2" // bad; my fault
For libraries, it often works to put the package code in the repo root:
"github.com/golang/oauth2" // package oauth2
Also avoid upper case letters (not all file systems are case sensitive).
16Many examples in this talk are from the standard library.
The standard library is a great place to find good Go code.
Look to it for inspiration.
But be warned:
When the standard library was written, we were still learning.
Most of it we got right, but we made some mistakes.
Use short names.
Think about context.
Use your judgment.
18