blob: c5dbbd2b00c628154768127ea3df6d697690c2c6 [file] [log] [blame] [view]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11001# Go Code Review Comments
2
3This page collects common comments made during reviews of Go code, so
4that a single detailed explanation can be referred to by shorthands.
5This is a laundry list of common mistakes, not a style guide.
6
7You can view this as a supplement to http://golang.org/doc/effective_go.html.
8
9**Please discuss changes before editing this page**, even _minor_ ones. Many people have opinions and this is not the place for edit wars.
10
Steve Streetingba290542015-07-28 15:04:30 +010011* [goimports](#goimports)
nathany4d6a1bf2014-12-10 22:00:35 -080012* [Comment Sentences](#comment-sentences)
Earl J. Wagner7dda73c2015-01-05 11:43:49 -060013* [Declaring Empty Slices](#declaring-empty-slices)
nathany4d6a1bf2014-12-10 22:00:35 -080014* [Doc Comments](#doc-comments)
15* [Don't Panic](#dont-panic)
16* [Error Strings](#error-strings)
17* [Handle Errors](#handle-errors)
18* [Imports](#imports)
19* [Import Dot](#import-dot)
20* [Indent Error Flow](#indent-error-flow)
21* [Initialisms](#initialisms)
22* [Line Length](#line-length)
23* [Mixed Caps](#mixed-caps)
24* [Named Result Parameters](#named-result-parameters)
25* [Naked Returns](#naked-returns)
26* [Package Comments](#package-comments)
27* [Package Names](#package-names)
28* [Pass Values](#pass-values)
29* [Receiver Names](#receiver-names)
30* [Receiver Type](#receiver-type)
31* [Useful Test Failures](#useful-test-failures)
32* [Variable Names](#variable-names)
33
Steve Streetingba290542015-07-28 15:04:30 +010034## goimports
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110035
Steve Streetingba290542015-07-28 15:04:30 +010036Run [goimports](https://github.com/bradfitz/goimports) on your code to automatically fix the majority of mechanical style issues as per `gofmt` (which almost all Go code uses) but also fixes unnecessary imports. As a result the import ordering can be slightly different after goimports so it helps us if you use it. You can configure your editor to run goimports on save, for example with GoSublime for Sublime Text or go-plus for Atom - this is recommended. The rest of this document addresses non-mechanical style points.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110037
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110038## Comment Sentences
39
40See http://golang.org/doc/effective_go.html#commentary. Comments documenting declarations should be full sentences, even if that seems a little redundant. This approach makes them format well when extracted into godoc documentation. Comments should begin with the name of the thing being described and end in a period:
41
nathany4d6a1bf2014-12-10 22:00:35 -080042```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110043// A Request represents a request to run a command.
44type Request struct { ...
45
46// Encode writes the JSON encoding of req to w.
47func Encode(w io.Writer, req *Request) { ...
48```
49
50and so on.
51
Earl J. Wagner7dda73c2015-01-05 11:43:49 -060052## Declaring Empty Slices
53
Earl J. Wagnere3ee7b02015-01-11 15:20:33 -060054When declaring a slice, prefer
Earl J. Wagner7dda73c2015-01-05 11:43:49 -060055```go
56var t []string
57```
58to
59```go
60t := []string{}
61```
62
Earl J. Wagnere3ee7b02015-01-11 15:20:33 -060063The former avoids allocating memory if the slice is never appended to.
Earl J. Wagner7dda73c2015-01-05 11:43:49 -060064
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110065## Doc Comments
66
67All top-level, exported names should have doc comments, as should non-trivial unexported type or function declarations. See http://golang.org/doc/effective_go.html#commentary for more information about commentary conventions.
68
69## Don't Panic
70
71See http://golang.org/doc/effective_go.html#errors. Don't use panic for normal error handling. Use error and multiple return values.
72
73## Error Strings
74
nathany4d6a1bf2014-12-10 22:00:35 -080075Error strings should not be capitalized (unless beginning with proper nouns or acronyms) or end with punctuation, since they are usually printed following other context. That is, use `fmt.Errorf("something bad")` not `fmt.Errorf("Something bad")`, so that `log.Print("Reading %s: %v", filename, err)` formats without a spurious capital letter mid-message. This does not apply to logging, which is implicitly line-oriented and not combined inside other messages.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110076
77## Handle Errors
78
Dave Day0d6986a2014-12-10 15:02:18 +110079See http://golang.org/doc/effective_go.html#errors. Do not discard errors using `_` variables. If a function returns an error, check it to make sure the function succeeded. Handle the error, return it, or, in truly exceptional situations, panic.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110080
81## Imports
82
83Imports are organized in groups, with blank lines between them. The standard library packages are in the first group.
84
nathany4d6a1bf2014-12-10 22:00:35 -080085```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110086package main
87
88import (
Dave Day0d6986a2014-12-10 15:02:18 +110089 "fmt"
90 "hash/adler32"
91 "os"
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110092
Dave Day0d6986a2014-12-10 15:02:18 +110093 "appengine/foo"
94 "appengine/user"
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110095
Dave Day0d6986a2014-12-10 15:02:18 +110096 "code.google.com/p/x/y"
97 "github.com/foo/bar"
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110098)
99```
100
nathany4d6a1bf2014-12-10 22:00:35 -0800101<a href="https://godoc.org/golang.org/x/tools/cmd/goimports">goimports</a> will do this for you.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100102
103## Import Dot
104
105The import . form can be useful in tests that, due to circular dependencies, cannot be made part of the package being tested:
106
nathany4d6a1bf2014-12-10 22:00:35 -0800107```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100108package foo_test
109
110import (
Dave Day0d6986a2014-12-10 15:02:18 +1100111 "bar/testutil" // also imports "foo"
112 . "foo"
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100113)
114```
115
116In this case, the test file cannot be in package foo because it uses bar/testutil, which imports foo. So we use the 'import .' form to let the file pretend to be part of package foo even though it is not. Except for this one case, do not use import . in your programs. It makes the programs much harder to read because it is unclear whether a name like Quux is a top-level identifier in the current package or in an imported package.
117
118## Indent Error Flow
119
nathany4d6a1bf2014-12-10 22:00:35 -0800120Try to keep the normal code path at a minimal indentation, and indent the error handling, dealing with it first. This improves the readability of the code by permitting visually scanning the normal path quickly. For instance, don't write:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100121
nathany4d6a1bf2014-12-10 22:00:35 -0800122```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100123if err != nil {
Dave Day0d6986a2014-12-10 15:02:18 +1100124 // error handling
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100125} else {
Dave Day0d6986a2014-12-10 15:02:18 +1100126 // normal code
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100127}
128```
129
nathany4d6a1bf2014-12-10 22:00:35 -0800130Instead, write:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100131
nathany4d6a1bf2014-12-10 22:00:35 -0800132```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100133if err != nil {
Dave Day0d6986a2014-12-10 15:02:18 +1100134 // error handling
135 return // or continue, etc.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100136}
137// normal code
138```
139
nathany4d6a1bf2014-12-10 22:00:35 -0800140If the if statement has an initialization statement that, such as:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100141
nathany4d6a1bf2014-12-10 22:00:35 -0800142```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100143if x, err := f(); err != nil {
Dave Day0d6986a2014-12-10 15:02:18 +1100144 // error handling
145 return
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100146} else {
Dave Day0d6986a2014-12-10 15:02:18 +1100147 // use x
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100148}
149```
150
151then this may require moving the short variable declaration to its own line:
152
nathany4d6a1bf2014-12-10 22:00:35 -0800153```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100154x, err := f()
155if err != nil {
Dave Day0d6986a2014-12-10 15:02:18 +1100156 // error handling
157 return
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100158}
159// use x
160```
161
162## Initialisms
163
164Words in names that are initialisms or acronyms (e.g. "URL" or "NATO") have a consistent case. For example, "URL" should appear as "URL" or "url" (as in "urlPony", or "URLPony"), never as "Url". Here's an example: ServeHTTP not ServeHttp.
165
166This rule also applies to "ID" when it is short for "identifier," so write "appID" instead of "appId".
167
168Code generated by the protocol buffer compiler is exempt from this rule. Human-written code is held to a higher standard than machine-written code.
169
170## Line Length
171
172There is no rigid line length limit in Go code, but avoid uncomfortably long lines. Similarly, don't add line breaks to keep lines short when they are more readable long--for example, if they are repetitive.
173
174Comments are typically wrapped before no more than 80 characters, not because it's a rule, but because it's more readable when viewing in an editor that might be sized to show hundreds of columns wide. Humans are better at following narrow text (e.g. columns in a newspaper) than giant walls of wide text, as a wide editor might show. Regardless, godoc should render it nicely either way.
175
176## Mixed Caps
177
Dave Day0d6986a2014-12-10 15:02:18 +1100178See http://golang.org/doc/effective_go.html#mixed-caps. This applies even when it breaks conventions in other languages. For example an unexported constant is `maxLength` not `MaxLength` or `MAX_LENGTH`.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100179
180## Named Result Parameters
181
182Consider what it will look like in godoc. Named result parameters like:
183
nathany4d6a1bf2014-12-10 22:00:35 -0800184```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100185func (n *Node) Parent1() (node *Node)
186func (n *Node) Parent2() (node *Node, err error)
187```
nathany4d6a1bf2014-12-10 22:00:35 -0800188
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100189will stutter in godoc; better to use:
nathany4d6a1bf2014-12-10 22:00:35 -0800190
191```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100192func (n *Node) Parent1() *Node
193func (n *Node) Parent2() (*Node, error)
194```
195
196On the other hand, if a function returns two or three parameters of the same type, or if the meaning of a result isn't clear from context, adding names may be useful. For example:
197
198```go
Dave Day0d6986a2014-12-10 15:02:18 +1100199func (f *Foo) Location() (float64, float64, error)
200```
nathany4d6a1bf2014-12-10 22:00:35 -0800201
202is less clear than:
203
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100204```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100205// Location returns f's latitude and longitude.
206// Negative values mean south and west, respectively.
Dave Day0d6986a2014-12-10 15:02:18 +1100207func (f *Foo) Location() (lat, long float64, err error)
208```
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100209
210Naked returns are okay if the function is a handful of lines. Once it's a medium-sized function, be explicit with your return values. Corollary: it's not worth it to name result parameters just because it enables you to use naked returns. Clarity of docs is always more important than saving a line or two in your function.
211
212Finally, in some cases you need to name a result parameter in order to change it in a deferred closure. That is always okay.
213
214## Naked Returns
215
nathany812cb132014-12-10 22:35:33 -0800216See [Named Result Parameters](#named-result-parameters).
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100217
218## Package Comments
219
220Package comments, like all comments to be presented by godoc, must appear adjacent to the package clause, with no blank line.
221
nathany4d6a1bf2014-12-10 22:00:35 -0800222```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100223// Package math provides basic constants and mathematical functions.
224package math
225```
226
nathany4d6a1bf2014-12-10 22:00:35 -0800227```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100228/*
229Package template implements data-driven templates for generating textual
230output such as HTML.
231....
232*/
233package template
234```
235
236See http://golang.org/doc/effective_go.html#commentary for more information about commentary conventions.
237
238## Package Names
239
240All references to names in your package will be done using the package name, so you can omit that name from the identifiers. For example, if you are in package chubby, you don't need type ChubbyFile, which clients will write as chubby.ChubbyFile. Instead, name the type File, which clients will write as chubby.File. See http://golang.org/doc/effective_go.html#package-names for more.
241
242## Pass Values
243
Dave Day0d6986a2014-12-10 15:02:18 +1100244Don't pass pointers as function arguments just to save a few bytes. If a function refers to its argument `x` only as `*x` throughout, then the argument shouldn't be a pointer. Common instances of this include passing a pointer to a string (`*string`) or a pointer to an interface value (`*io.Reader`). In both cases the value itself is a fixed size and can be passed directly. This advice does not apply to large structs, or even small structs that might grow.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100245
246## Receiver Names
247
248The name of a method's receiver should be a reflection of its identity; often a one or two letter abbreviation of its type suffices (such as "c" or "cl" for "Client"). Don't use generic names such as "me", "this" or "self", identifiers typical of object-oriented languages that place more emphasis on methods as opposed to functions. The name need not be as descriptive as a that of a method argument, as its role is obvious and serves no documentary purpose. It can be very short as it will appear on almost every line of every method of the type; familiarity admits brevity. Be consistent, too: if you call the receiver "c" in one method, don't call it "cl" in another.
249
250## Receiver Type
251
252Choosing whether to use a value or pointer receiver on methods can be difficult, especially to new Go programmers. If in doubt, use a pointer, but there are times when a value receiver makes sense, usually for reasons of efficiency, such as for small unchanging structs or values of basic type. Some rules of thumb:
253
254 * If the receiver is a map, func or chan, don't use a pointer to it.
255 * If the receiver is a slice and the method doesn't reslice or reallocate the slice, don't use a pointer to it.
256 * If the method needs to mutate the receiver, the receiver must be a pointer.
257 * If the receiver is a struct that contains a sync.Mutex or similar synchronizing field, the receiver must be a pointer to avoid copying.
258 * If the receiver is a large struct or array, a pointer receiver is more efficient. How large is large? Assume it's equivalent to passing all its elements as arguments to the method. If that feels too large, it's also too large for the receiver.
259 * Can function or methods, either concurrently or when called from this method, be mutating the receiver? A value type creates a copy of the receiver when the method is invoked, so outside updates will not be applied to this receiver. If changes must be visible in the original receiver, the receiver must be a pointer.
260 * If the receiver is a struct, array or slice and any of its elements is a pointer to something that might be mutating, prefer a pointer receiver, as it will make the intention more clear to the reader.
261 * If the receiver is a small array or struct that is naturally a value type (for instance, something like the time.Time type), with no mutable fields and no pointers, or is just a simple basic type such as int or string, a value receiver makes sense. A value receiver can reduce the amount of garbage that can be generated; if a value is passed to a value method, an on-stack copy can be used instead of allocating on the heap. (The compiler tries to be smart about avoiding this allocation, but it can't always succeed.) Don't choose a value receiver type for this reason without profiling first.
262 * Finally, when in doubt, use a pointer receiver.
263
264## Useful Test Failures
265
266Tests should fail with helpful messages saying what was wrong, with what inputs, what was actually got, and what was expected. It may be tempting to write a bunch of assertFoo helpers, but be sure your helpers produce useful error messages. Assume that the person debugging your failing test is not you, and is not your team. A typical Go test fails like:
267
nathany4d6a1bf2014-12-10 22:00:35 -0800268```go
Dave Day0d6986a2014-12-10 15:02:18 +1100269if got != tt.want {
270 t.Errorf("Foo(%q) = %d; want %d", tt.in, got, tt.want) // or Fatalf, if test can't test anything more past this point
271}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100272```
273
274Note that the order here is actual != expected, and the message uses that order too. Some test frameworks encourage writing these backwards: 0 != x, "expected 0, got x", and so on. Go does not.
275
nathany4d6a1bf2014-12-10 22:00:35 -0800276If that seems like a lot of typing, you may want to write a [[table-driven test|TableDrivenTests]].
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100277
278Another common technique to disambiguate failing tests when using a test helper with different input is to wrap each caller with a different TestFoo function, so the test fails with that name:
279
nathany4d6a1bf2014-12-10 22:00:35 -0800280```go
Dave Day0d6986a2014-12-10 15:02:18 +1100281func TestSingleValue(t *testing.T) { testHelper(t, []int{80}) }
282func TestNoValues(t *testing.T) { testHelper(t, []int{}) }
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100283```
284
285In any case, the onus is on you to fail with a helpful message to whoever's debugging your code in the future.
286
287## Variable Names
288
289Variable names in Go should be short rather than long. This is especially true for local variables with limited scope. Prefer c to lineCount. Prefer i to sliceIndex.
290
Dave Day0d6986a2014-12-10 15:02:18 +1100291The basic rule: the further from its declaration that a name is used, the more descriptive the name must be. For a method receiver, one or two letters is sufficient. Common variables such as loop indices and readers can be a single letter (`i`, `r`). More unusual things and global variables need more descriptive names.