mirror of
https://github.com/golang/go
synced 2024-11-12 07:10:22 -07:00
11e4db7c12
R=rsc DELTA=125 (13 added, 62 deleted, 50 changed) OCL=33545 CL=33550
809 lines
22 KiB
HTML
809 lines
22 KiB
HTML
|
|
<h2 id="introduction">Introduction</h2>
|
|
|
|
<p>
|
|
Go is a new language. Although it's in the C family
|
|
it has some unusual properties that make effective Go programs
|
|
different in character from programs in existing languages.
|
|
A straightforward translation of a C++ or Java program into Go
|
|
is unlikely to produce a satisfactory result—Java programs
|
|
are written in Java, not Go.
|
|
On the other hand, thinking about the problem from a Go
|
|
perspective could produce a successful but quite different
|
|
program.
|
|
In other words,
|
|
to write Go well, it's important to understand its properties
|
|
and idioms.
|
|
It's also important to know the established conventions for
|
|
programming in Go, such as naming, formatting, program
|
|
construction, and so on, so that programs you write
|
|
will be easy for other Go programmers to understand.
|
|
</p>
|
|
|
|
<p>
|
|
This document gives tips for writing clear, idiomatic Go code.
|
|
It augments the <a href="go_spec.html">language specification</a>
|
|
and the <a href="go_tutorial.html">tutorial</a>, both of which you
|
|
should read first.
|
|
</p>
|
|
|
|
<h3 id="read">Examples</h3>
|
|
|
|
<p>
|
|
The <a href="/src/pkg/">Go package sources</a>
|
|
are intended to serve not
|
|
only as the core library but also as examples of how to
|
|
use the language.
|
|
If you have a question about how to approach a problem or how something
|
|
might be implemented they can provide answers, ideas and
|
|
background.
|
|
</p>
|
|
|
|
|
|
<h2 id="formatting">Formatting</h2>
|
|
|
|
<p>
|
|
Formatting issues are the most contentious
|
|
but the least consequential.
|
|
People can adapt to different formatting styles
|
|
but it's better if they don't have to, and
|
|
less time is devoted to the topic
|
|
if everyone adheres to the same style.
|
|
The problem is how to approach this Utopia without a long
|
|
prescriptive style guide.
|
|
</p>
|
|
|
|
<p>
|
|
With Go we take an unusual
|
|
approach and let the machine
|
|
take care of most formatting issues.
|
|
A program, <code>gofmt</code>, reads a Go program
|
|
and emits the source in a standard style of indentation
|
|
and vertical alignment, retaining and if necessary
|
|
reformatting comments.
|
|
If you want to know how to handle some new layout
|
|
situation, run <code>gofmt</code>; if the answer doesn't
|
|
seem right, fix the program (or file a bug), don't work around it.
|
|
</p>
|
|
|
|
<p>
|
|
As an example, there's no need to spend time lining up
|
|
the comments on the fields of a structure.
|
|
<code>Gofmt</code> will do that for you. Given the
|
|
declaration
|
|
</p>
|
|
|
|
<pre>
|
|
type T struct {
|
|
name string; // name of the object
|
|
value int; // its value
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
<code>gofmt</code> will make the columns line up:
|
|
</p>
|
|
|
|
<pre>
|
|
type T struct {
|
|
name string; // name of the object
|
|
value int; // its value
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
All code in the libraries has been formatted with <code>gofmt</code>.
|
|
<font color=red>TODO</font>
|
|
</p>
|
|
|
|
|
|
<p>
|
|
Some formatting details remain. Very briefly:
|
|
</p>
|
|
|
|
<dl>
|
|
<dt>Indentation</dt>
|
|
<dd>We use tabs for indentation and <code>gofmt</code> emits them by default.
|
|
Use spaces if you must.
|
|
</dd>
|
|
<dt>Line length</dt>
|
|
<dd>
|
|
Go has no line length limit. Don't worry about overflowing a punched card.
|
|
If a line feels too long, wrap it and indent with an extra tab.
|
|
</dd>
|
|
<dt>Parentheses</dt>
|
|
<dd>
|
|
Go needs fewer parentheses: control structures (<code>if</code>,
|
|
<code>for</code>, <code>switch</code>) do not have parentheses in
|
|
their syntax.
|
|
Also, the operator precedence hierarchy is shorter and clearer, so
|
|
<pre>
|
|
x<<8 + y<<16
|
|
</pre>
|
|
means what the spacing implies.
|
|
</dd>
|
|
</dl>
|
|
|
|
<h2>Commentary</h2>
|
|
|
|
<p>
|
|
Go provides C-style <code>/* */</code> block comments
|
|
and C++-style <code>//</code> line comments.
|
|
Line comments are the norm;
|
|
block comments appear mostly as package comments and
|
|
are also useful to disable large swaths of code.
|
|
</p>
|
|
|
|
<p>
|
|
The program—and web server—<code>godoc</code> processes
|
|
Go source files to extract documentation about the contents of the
|
|
package.
|
|
Comments that appear before top-level declarations, with no intervening newlines,
|
|
are extracted along with the declaration to serve as explanatory text for the item.
|
|
The nature and style of these comments determines the
|
|
quality of the documentation <code>godoc</code> produces.
|
|
</p>
|
|
|
|
<p>
|
|
Every package should have a <i>package comment</i>, a block
|
|
comment preceding the package clause.
|
|
For multi-file packages, the package comment only needs to be
|
|
present in one file, and any one will do.
|
|
The package comment should introduce the package and
|
|
provide information relevant to the package as a whole.
|
|
It will appear first on the <code>godoc</code> page and
|
|
should set up the detailed documentation that follows.
|
|
</p>
|
|
|
|
<pre>
|
|
/*
|
|
The regexp package implements a simple library for
|
|
regular expressions.
|
|
|
|
The syntax of the regular expressions accepted is:
|
|
|
|
regexp:
|
|
concatenation { '|' concatenation }
|
|
concatenation:
|
|
{ closure }
|
|
closure:
|
|
term [ '*' | '+' | '?' ]
|
|
term:
|
|
'^'
|
|
'$'
|
|
'.'
|
|
character
|
|
'[' [ '^' ] character-ranges ']'
|
|
'(' regexp ')'
|
|
*/
|
|
package regexp
|
|
</pre>
|
|
|
|
<p>
|
|
If the package is simple, the package comment can be brief.
|
|
</p>
|
|
|
|
<pre>
|
|
// The path package implements utility routines for
|
|
// manipulating slash-separated filename paths.
|
|
</pre>
|
|
|
|
<p>
|
|
Comments do not need extra formatting such as banners of stars.
|
|
The generated output may not even be presented in a fixed-width font, so don't depend
|
|
on spacing for alignment—<code>godoc</code>, like <code>gofmt</code>,
|
|
takes care of that.
|
|
Finally, the comments are uninterpreted plain text, so HTML and other
|
|
annotations such as <code>_this_</code> will reproduce <i>verbatim</i> and should
|
|
not be used.
|
|
</p>
|
|
|
|
<p>
|
|
Inside a package, any comment immediately preceding a top-level declaration
|
|
serves as a <i>doc comment</i> for that declaration.
|
|
Every exported (capitalized) name in a program should
|
|
have a doc comment.
|
|
</p>
|
|
|
|
<p>
|
|
Doc comments work best as complete English sentences, which allow
|
|
a wide variety of automated presentations.
|
|
The first sentence should be a one-sentence summary that
|
|
starts with the name being declared:
|
|
</p>
|
|
|
|
<pre>
|
|
// Compile parses a regular expression and returns, if successful, a Regexp
|
|
// object that can be used to match against text.
|
|
func Compile(str string) (regexp *Regexp, error os.Error) {
|
|
</pre>
|
|
|
|
<p>
|
|
Go's declaration syntax allows grouping of declarations.
|
|
A single doc comment can introduce a group of related constants or variables.
|
|
Since the whole declaration is presented, such a comment can often be perfunctory.
|
|
</p>
|
|
|
|
<pre>
|
|
// Error codes returned by failures to parse an expression.
|
|
var (
|
|
ErrInternal = os.NewError("internal error");
|
|
ErrUnmatchedLpar = os.NewError("unmatched '('");
|
|
ErrUnmatchedRpar = os.NewError("unmatched ')'");
|
|
...
|
|
)
|
|
</pre>
|
|
|
|
<p>
|
|
Even for private names, grouping can also indicate relationships between items,
|
|
such as the fact that a set of variables is controlled by a mutex.
|
|
</p>
|
|
|
|
<pre>
|
|
var (
|
|
countLock sync.Mutex;
|
|
inputCount uint32;
|
|
outputCount uint32;
|
|
errorCount uint32;
|
|
)
|
|
</pre>
|
|
|
|
<h2 id="names">Names</h2>
|
|
|
|
<h3 id="mixed-caps">Use MixedCaps</h3>
|
|
|
|
<p>
|
|
Go uses the case of the first letter in a name to decide
|
|
whether the name is visible in other packages.
|
|
Multiword names use MixedCaps or mixedCaps
|
|
rather than underscores.
|
|
</p>
|
|
|
|
<h3 id="package-names">Use short package names</h3>
|
|
|
|
<p>
|
|
Package names are lower case single-word names:
|
|
there should be no need for underscore or mixedCaps.
|
|
The package name is conventionally the base name of
|
|
the source directory: the package in <code>src/pkg/container/vector</code>
|
|
is installed as <code>"container/vector"</code> but has name <code>vector</code>,
|
|
not <code>container_vector</code> and not <code>containerVector</code>.
|
|
The package name is only the default name used
|
|
when importing the package; it need not be unique
|
|
across all source code.
|
|
</p>
|
|
|
|
<h3 id="name-length">Avoid long names</h3>
|
|
|
|
<p>
|
|
A name's length should not exceed its information content.
|
|
For a function-local variable
|
|
in scope only for a few lines, the name <code>i</code> conveys just
|
|
as much information as <code>index</code> or <code>idx</code> and is easier to read.
|
|
Letters are easier to distinguish than numbers; use <code>i</code> and <code>j</code>
|
|
not <code>i1</code> and <code>i2</code>.
|
|
</p>
|
|
|
|
<p>
|
|
Exported names must convey more information
|
|
because they appear far from their origin.
|
|
Even so, longer names are not always better,
|
|
and the package name can help convey information:
|
|
the buffered <code>Reader</code> is <code>bufio.Reader</code>, not <code>bufio.BufReader</code>.
|
|
Similarly, <code>once.Do</code> is as precise and evocative as
|
|
<code>once.DoOrWaitUntilDone</code>, and <code>once.Do(f)</code> reads
|
|
better than <code>once.DoOrWaitUntilDone(f)</code>.
|
|
Encoding small essays into function names is not Go style;
|
|
using clear names supported by good documentation is.
|
|
</p>
|
|
|
|
<h3 id="interfacers">Use the -er convention for interface names</h3>
|
|
|
|
<p>
|
|
One-method interfaces are conventionally named by
|
|
the method name plus the -er suffix: <code>Reader</code>,
|
|
<code>Writer</code>, <code>Formatter</code>.
|
|
</p>
|
|
|
|
<h3 id="common-names">Use canonical names</h3>
|
|
|
|
<p>
|
|
XXX permits interfaces String() not ToString() XXX
|
|
A few method names—<code>Read</code>, <code>Write</code>, <code>Close</code>, <code>Flush</code>, <code>String</code>—have
|
|
canonical signatures and meanings. To avoid confusion,
|
|
don't give your method one of those names unless it
|
|
has the same signature and meaning.
|
|
Conversely, if your type implements a method with the
|
|
same meaning as a method on a well-known type,
|
|
give it the same name and signature.
|
|
</p>
|
|
|
|
<p>
|
|
Some function-local variables have canonical names too.
|
|
Just as <code>i</code> is idiomatic in Go for an
|
|
index variable, <code>n</code> is idiomatic for a count, <code>b</code> for a <code>[]byte</code>,
|
|
<code>s</code> for a <code>string</code>, <code>r</code> for a <code>Reader</code>,
|
|
<code>err</code> for an <code>os.Error</code>
|
|
and so on.
|
|
Don't mix shorthands: it is especially confusing to
|
|
have two different variables <code>i</code> and <code>idx</code>,
|
|
or <code>n</code> and <code>cnt</code>.
|
|
</p>
|
|
|
|
<h2 id="idioms">Idioms</h2>
|
|
|
|
<h3 id="struct-allocation">Allocate using literals</h3>
|
|
|
|
<p>
|
|
A struct literal is an expression that creates a
|
|
new instance each time it is evaluated. The address of such
|
|
an expression points to a fresh instance each time.
|
|
Use such expressions to avoid the repetition of filling
|
|
out a data structure.
|
|
</p>
|
|
|
|
<pre>
|
|
length := Point{x, y}.Abs();
|
|
</pre>
|
|
|
|
<pre>
|
|
// Prepare RPCMessage to send to server
|
|
rpc := &RPCMessage {
|
|
Version: 1,
|
|
Header: &RPCHeader {
|
|
Id: nextId(),
|
|
Signature: sign(body),
|
|
Method: method,
|
|
},
|
|
Body: body,
|
|
};
|
|
</pre>
|
|
|
|
<h3 id="buffer-slice">Use parallel assignment to slice a buffer</h3>
|
|
|
|
<pre>
|
|
header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n];
|
|
</pre>
|
|
|
|
<h2 id="control-flow">Control Flow</h2>
|
|
|
|
<h3 id="else">Omit needless else bodies</h3>
|
|
|
|
<p>
|
|
When an <code>if</code> statement doesn't flow into the next statement—that is,
|
|
the body ends in <code>break</code>, <code>continue</code>,
|
|
<code>goto</code>, or <code>return</code>—omit the <code>else</code>.
|
|
</p>
|
|
|
|
<pre>
|
|
f, err := os.Open(name, os.O_RDONLY, 0);
|
|
if err != nil {
|
|
return err;
|
|
}
|
|
codeUsing(f);
|
|
</pre>
|
|
|
|
<h3 id="switch">Switch</h3>
|
|
|
|
<p>
|
|
Go's <code>switch</code> is more general than C's.
|
|
When an <code>if</code>-<code>else</code>-<code>if</code>-<code>else</code>
|
|
chain has three or more bodies,
|
|
or an <code>if</code> condition has a long list of alternatives,
|
|
it will be clearer if rewritten as a <code>switch</code>.
|
|
</p>
|
|
|
|
<a href="/src/pkg/http/url.go">go/src/pkg/http/url.go</a>:
|
|
<pre>
|
|
func unhex(c byte) byte {
|
|
switch {
|
|
case '0' <= c && c <= '9':
|
|
return c - '0'
|
|
case 'a' <= c && c <= 'f':
|
|
return c - 'a' + 10
|
|
case 'A' <= c && c <= 'F':
|
|
return c - 'A' + 10
|
|
}
|
|
return 0
|
|
}
|
|
</pre>
|
|
|
|
<a href="/src/pkg/http/url.go">go/src/pkg/http/url.go</a>:
|
|
<pre>
|
|
func shouldEscape(c byte) bool {
|
|
switch c {
|
|
case ' ', '?', '&', '=', '#', '+', '%':
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
</pre>
|
|
|
|
<a href="/src/pkg/bytes/bytes.go">go/src/pkg/bytes/bytes.go</a>:
|
|
<pre>
|
|
// Compare returns an integer comparing the two byte arrays
|
|
// lexicographically.
|
|
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b
|
|
func Compare(a, b []byte) int {
|
|
for i := 0; i < len(a) && i < len(b); i++ {
|
|
switch {
|
|
case a[i] > b[i]:
|
|
return 1
|
|
case a[i] < b[i]:
|
|
return -1
|
|
}
|
|
}
|
|
switch {
|
|
case len(a) < len(b):
|
|
return -1
|
|
case len(a) > len(b):
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
</pre>
|
|
|
|
<h2 id="functions">Functions</h2>
|
|
|
|
<h3 id="omit-wrappers">Omit needless wrappers</h3>
|
|
|
|
<p>
|
|
Functions are great for factoring out common code, but
|
|
if a function is only called once,
|
|
ask whether it is necessary,
|
|
especially if it is just a short wrapper around another function.
|
|
This style is rampant in C++ code: wrappers
|
|
call wrappers that call wrappers that call wrappers.
|
|
This style hinders people trying to understand the program,
|
|
not to mention computers trying to execute it.
|
|
</p>
|
|
|
|
<h3 id="multiple-returns">Return multiple values</h3>
|
|
|
|
<p>
|
|
If a function must return multiple values, it can
|
|
do so directly.
|
|
There is no need to pass a pointer to a return value.
|
|
</p>
|
|
|
|
<h2 id="errors">Errors</h2>
|
|
|
|
<h3 id="error-returns">Return <code>os.Error</code>, not <code>bool</code></h3>
|
|
|
|
<p>
|
|
Especially in libraries, functions tend to have multiple error modes.
|
|
Instead of returning a boolean to signal success,
|
|
return an <code>os.Error</code> that describes the failure.
|
|
Even if there is only one failure mode now,
|
|
there may be more later.
|
|
</p>
|
|
|
|
<h3 id="handle-errors-first">Handle errors first</h3>
|
|
|
|
<p>
|
|
Error cases tend to be simpler than non-error cases,
|
|
and it helps readability when the non-error flow
|
|
of control is always down the page.
|
|
Also, error cases tend to end in <code>return</code> statements,
|
|
so that there is <a href="#else">no need for an explicit else</a>.
|
|
</p>
|
|
|
|
<pre>
|
|
if len(name) == 0 {
|
|
return os.EINVAL;
|
|
}
|
|
if IsDir(name) {
|
|
return os.EISDIR;
|
|
}
|
|
f, err := os.Open(name, os.O_RDONLY, 0);
|
|
if err != nil {
|
|
return err;
|
|
}
|
|
codeUsing(f);
|
|
</pre>
|
|
|
|
<h3 id="error-context">Return structured errors</h3>
|
|
|
|
Implementations of <code>os.Error</code> should
|
|
describe the error and provide context.
|
|
For example, <code>os.Open</code> returns an <code>os.PathError</code>:
|
|
|
|
<a href="/src/pkg/os/file.go">/src/pkg/os/file.go</a>:
|
|
<pre>
|
|
// PathError records an error and the operation and
|
|
// file path that caused it.
|
|
type PathError struct {
|
|
Op string;
|
|
Path string;
|
|
Error Error;
|
|
}
|
|
|
|
func (e *PathError) String() string {
|
|
return e.Op + " " + e.Path + ": " + e.Error.String();
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
<code>PathError</code>'s <code>String</code> formats
|
|
the error nicely, including the operation and file name
|
|
tha failed; just printing the error generates a
|
|
message, such as
|
|
</p>
|
|
<pre>
|
|
open /etc/passwx: no such file or directory
|
|
</pre>
|
|
<p>
|
|
that is useful even if printed far from the call that
|
|
triggered it.
|
|
</p>
|
|
|
|
<p>
|
|
Callers that care about the precise error details can
|
|
use a type switch or a type guard to look for specific
|
|
errors and extract details. For <code>PathErrors</code>
|
|
this might include examining the internal <code>Error</code>
|
|
to see if it is <code>os.EPERM</code> or <code>os.ENOENT</code>,
|
|
for instance.
|
|
</p>
|
|
|
|
<h2 id="types">Programmer-defined types</h2>
|
|
|
|
<h3 id="constructors">Use <code>NewTypeName</code> for constructors</h3>
|
|
|
|
<p>
|
|
The constructor for the type <code>pkg.MyType</code> should
|
|
be named <code>pkg.NewMyType</code> and should return <code>*pkg.MyType</code>.
|
|
The implementation of <code>NewTypeName</code> often uses the
|
|
<a href="#struct-allocation">struct allocation idiom</a>.
|
|
</p>
|
|
|
|
<a href="xxx">go/src/pkg/os/file.go</a>:
|
|
<pre>
|
|
func NewFile(fd int, name string) *File {
|
|
if file < 0 {
|
|
return nil
|
|
}
|
|
return &File{fd, name, nil, 0}
|
|
}
|
|
</pre>
|
|
|
|
<p>Packages that export only a single type can
|
|
shorten <code>NewTypeName</code> to <code>New</code>;
|
|
the vector constructor is
|
|
<code>vector.New</code>, not <code>vector.NewVector</code>.
|
|
</p>
|
|
|
|
<p>
|
|
A type that is intended to be allocated
|
|
as part of a larger struct may have an <code>Init</code> method
|
|
that must be called explicitly.
|
|
Conventionally, the <code>Init</code> method returns
|
|
the object being initialized, to make the constructor trivial:
|
|
</p>
|
|
|
|
<a href="xxx">go/src/pkg/container/vector/vector.go</a>:
|
|
<pre>
|
|
func New(len int) *Vector {
|
|
return new(Vector).Init(len)
|
|
}
|
|
</pre>
|
|
|
|
<h3 id="zero-value">Make the zero value meaningful</h3>
|
|
|
|
<p>
|
|
In Go, newly allocated memory and newly declared variables are zeroed.
|
|
If a type is intended to be allocated without using a constructor
|
|
(for example, as part of a larger struct or declared as a local variable),
|
|
define the meaning of the zero value and arrange for that meaning
|
|
to be useful.
|
|
</p>
|
|
|
|
<p>
|
|
For example, <code>sync.Mutex</code> does not
|
|
have an explicit constructor or <code>Init</code> method.
|
|
Instead, the zero value for a <code>sync.Mutex</code>
|
|
is defined to be an unlocked mutex.
|
|
</p>
|
|
|
|
<h2 id="interfaces">Interfaces</h2>
|
|
|
|
<h3 id="accept-interface-values">Accept interface values</h3>
|
|
|
|
buffered i/o takes a Reader, not an os.File. XXX
|
|
|
|
<h3 id="return-interface-values">Return interface values</h3>
|
|
|
|
<p>
|
|
If a type exists only to implement an interface
|
|
and has no exported methods beyond that interface,
|
|
there is no need to publish the type itself.
|
|
Instead, write a constructor that returns an interface value.
|
|
</p>
|
|
|
|
<p>
|
|
For example, both <code>crc32.NewIEEE()</code> and <code>adler32.New()</code>
|
|
return type <code>hash.Hash32</code>.
|
|
Substituting the CRC-32 algorithm for Adler-32 in a Go program
|
|
requires only changing the constructor call:
|
|
the rest of the code is unaffected by the change of algorithm.
|
|
</p>
|
|
|
|
<h3 id="asdf">Use interface adapters to expand an implementation</h3>
|
|
|
|
XXX
|
|
|
|
<h3 id="fdsa">Use anonymous fields to incorporate an implementation</h3>
|
|
|
|
XXX
|
|
|
|
<h2>Data-Driven Programming</h2>
|
|
|
|
<p>
|
|
tables
|
|
</p>
|
|
|
|
<p>
|
|
XXX struct tags for marshalling.
|
|
template
|
|
eventually datafmt
|
|
</p>
|
|
|
|
<h2>Concurrency</h2>
|
|
|
|
<h3 id="share-memory">Share memory by communicating</h3>
|
|
|
|
<p>
|
|
Do not communicate by sharing memory;
|
|
instead, share memory by communicating.
|
|
</p>
|
|
|
|
<p>
|
|
XXX, more here.
|
|
</p>
|
|
|
|
|
|
<h2>Testing</h2>
|
|
|
|
<h3 id="no-abort">Run tests to completion</h3>
|
|
|
|
<p>
|
|
Tests should not stop early just because one case has misbehaved.
|
|
If at all possible, let tests continue, in order to characterize the
|
|
problem in more detail.
|
|
For example, it is more useful for a test to report that <code>isPrime</code>
|
|
gives the wrong answer for 4, 8, 16 and 32 than to report
|
|
that <code>isPrime</code> gives the wrong answer for 4 and therefore
|
|
no more tests were run.
|
|
XXX
|
|
test bottom up
|
|
test runs top to bottom
|
|
how to use gotest
|
|
XXX
|
|
</p>
|
|
|
|
<h3 id="good-errors">Print useful errors when tests fail</h3>
|
|
|
|
<p>
|
|
If a test fails, print a concise message explaining the context,
|
|
what happened, and what was expected.
|
|
Many testing environments encourage causing the
|
|
program to crash, but stack traces and core dumps
|
|
have low signal to noise ratios and require reconstructing
|
|
the situation from scratch.
|
|
The programmer who triggers the test failure may be someone
|
|
editing the code months later or even someone editing a different
|
|
package on which the code depends.
|
|
Time invested writing a good error message now pays off when
|
|
the test breaks later.
|
|
</p>
|
|
|
|
<h3 id="data-driven-tests">Use data-driven tests</h3>
|
|
|
|
<p>
|
|
Many tests reduce to running the same code multiple times,
|
|
with different input and expected output.
|
|
Instead of using cut and paste to write this code,
|
|
create a table of test cases and write a single test that
|
|
iterates over the table.
|
|
Once the table is written, you might find that it
|
|
serves well as input to multiple tests. For example,
|
|
a single table of encoded/decoded pairs can be
|
|
used by both <code>TestEncoder</code> and <code>TestDecoder</code>.
|
|
</p>
|
|
|
|
<p>
|
|
This data-driven style dominates in the Go package tests.
|
|
<br>
|
|
<!-- search for for.*range here -->
|
|
</p>
|
|
|
|
<h3 id="reflect.DeepEqual">Use reflect.DeepEqual to compare complex values</h3>
|
|
|
|
<p>
|
|
The <code>reflect.DeepEqual</code> function tests
|
|
whether two complex data structures have equal values.
|
|
If a function returns a complex data structure,
|
|
<code>reflect.DeepEqual</code> combined with table-driven testing
|
|
makes it easy to check that the return value is
|
|
exactly as expected.
|
|
</p>
|
|
|
|
<h2 id="be-consistent">Be consistent</h2>
|
|
|
|
<p>
|
|
Programmers often want their style to be distinctive,
|
|
writing loops backwards or using custom spacing and
|
|
naming conventions. Such idiosyncracies come at a
|
|
price, however: by making the code look different,
|
|
they make it harder to understand.
|
|
Consistency trumps personal
|
|
expression in programming.
|
|
</p>
|
|
|
|
<p>
|
|
If a program does the same thing twice,
|
|
it should do it the same way both times.
|
|
Conversely, if two different sections of a
|
|
program look different, the reader will
|
|
expect them to do different things.
|
|
</p>
|
|
|
|
<p>
|
|
Consider <code>for</code> loops.
|
|
Traditionally, a loop over <code>n</code>
|
|
elements begins:
|
|
</p>
|
|
|
|
<pre>
|
|
for i := 0; i < n; i++ {
|
|
</pre>
|
|
|
|
<p>
|
|
Much of the time, the loop could run in the opposite order
|
|
and still be correct:
|
|
</p>
|
|
|
|
<pre>
|
|
for i := n-1; i >= 0; i-- {
|
|
</pre>
|
|
|
|
<p>
|
|
The convention
|
|
is to count up unless to do so would be incorrect.
|
|
A loop that counts down implicitly says “something
|
|
special is happening here.”
|
|
A reader who finds a program in which some
|
|
loops count up and the rest count down
|
|
will spend time trying to understand why.
|
|
</p>
|
|
|
|
<p>
|
|
Loop direction is just one
|
|
programming decision that must be made
|
|
consistently; others include
|
|
formatting, naming variables and methods,
|
|
whether a type
|
|
has a constructor, what tests look like, and so on.
|
|
Why is this variable called <code>n</code> here and <code>cnt</code> there?
|
|
Why is the <code>Log</code> constructor <code>CreateLog</code> when
|
|
the <code>List</code> constructor is <code>NewList</code>?
|
|
Why is this data structure initialized using
|
|
a structure literal when that one
|
|
is initialized using individual assignments?
|
|
These questions distract from the important one:
|
|
what does the code do?
|
|
Moreover, internal consistency is important not only within a single file,
|
|
but also within the the surrounding source files.
|
|
When editing code, read the surrounding context
|
|
and try to mimic it as much as possible, even if it
|
|
disagrees with the rules here.
|
|
It should not be possible to tell which lines
|
|
you wrote or edited based on style alone.
|
|
Consistency about little things
|
|
lets readers concentrate on big ones.
|
|
</p>
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|