What's in a name?

October 2014

Andrew Gerrand

Google Inc.

Names matter

Readability is the defining quality of good code.

Good names are critical to readability.

This talk is about naming in Go.

2

Good names

A good name is:

3

A rule of thumb

The greater the distance between a name's declaration and its uses,
the longer the name should be.

4

Use MixedCase

Names in Go should use MixedCase.

(Don't use names_with_underscores.)

Acronyms should be all capitals, as in ServeHTTP and IDProcessor.

5

Local variables

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.)

6

Bad

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
}
7

Good

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
}
8

Parameters

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
9

Return values

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)
10

Receivers

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.)

11

Exported package-level names

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.

12

Interface Types

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).

13

Errors

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")
14

Packages

Choose package names that lend meaning to the names they export.

Steer clear of util, common, and the like.

15

Import paths

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).

16

The standard library

Many 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.

17

Conclusion

Use short names.

Think about context.

Use your judgment.

18

Thank you

Andrew Gerrand

Google Inc.

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)