Merge pull request #729 from gaal/go

Go Style Guide
This commit is contained in:
Titus Winters 2022-11-17 13:56:41 -05:00 committed by GitHub
commit d976b652ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 7595 additions and 0 deletions

3053
go/best-practices.md Normal file

File diff suppressed because it is too large Load Diff

3876
go/decisions.md Normal file

File diff suppressed because it is too large Load Diff

483
go/guide.md Normal file
View File

@ -0,0 +1,483 @@
<!--* toc_depth: 3 *-->
# Go Style Guide
https://google.github.io/styleguide/go/guide
[Overview](index) | [Guide](guide) | [Decisions](decisions) |
[Best practices](best-practices)
<!--
-->
{% raw %}
**Note:** This is part of a series of documents that outline [Go Style](index)
at Google. This document is **[normative](index#normative) and
[canonical](index#canonical)**. See [the overview](index#about) for more
information.
<a id="principles"></a>
## Style principles
There are a few overarching principles that summarize how to think about writing
readable Go code. The following are attributes of readable code, in order of
importance:
1. **[Clarity]**: The code's purpose and rationale is clear to the reader.
1. **[Simplicity]**: The code accomplishes its goal in the simplest way
possible.
1. **[Concision]**: The code has a high signal-to-noise ratio.
1. **[Maintainability]**: The code is written such that it can be easily
maintained.
1. **[Consistency]**: The code is consistent with the broader Google codebase.
[Clarity]: #clarity
[Simplicity]: #simplicity
[Concision]: #concision
[Maintainability]: #maintainability
[Consistency]: #consistency
<a id="clarity"></a>
### Clarity
The core goal of readability is to produce code that is clear to the reader.
Clarity is primarily achieved with effective naming, helpful commentary, and
efficient code organization.
Clarity is to be viewed through the lens of the reader, not the author of the
code. It is more important that code be easy to read than easy to write. Clarity
in code has two distinct facets:
* [What is the code actually doing?](#clarity-purpose)
* [Why is the code doing what it does?](#clarity-rationale)
<a id="clarity-purpose"></a>
#### What is the code actually doing?
Go is designed such that it should be relatively straightforward to see what the
code is doing. In cases of uncertainty or where a reader may require prior
knowledge in order to understand the code, it is worth investing time in order
to make the code's purpose clearer for future readers. For example, it may help
to:
* Use more descriptive variable names
* Add additional commentary
* Break up the code with whitespace and comments
* Refactor the code into separate functions/methods to make it more modular
There is no one-size-fits-all approach here, but it is important to prioritize
clarity when developing Go code.
<a id="clarity-rationale"></a>
#### Why is the code doing what it does?
The code's rationale is often sufficiently communicated by the names of
variables, functions, methods, or packages. Where it is not, it is important to
add commentary. The "Why?" is especially important when the code contains
nuances that a reader may not be familiar with, such as:
* A nuance in the language, e.g., a closure will be capturing a loop variable,
but the closure is many lines away
* A nuance of the business logic, e.g., an access control check that needs to
distinguish between the actual user and someone impersonating a user
An API might require care to use correctly. For example, a piece of code may be
intricate and difficult to follow for performance reasons, or a complex sequence
of mathematical operations may use type conversions in an unexpected way. In
these cases and many more, it is important that accompanying commentary and
documentation explain these aspects so that future maintainers don't make a
mistake and so that readers can understand the code without needing to
reverse-engineer it.
It is also important to be aware that some attempts to provide clarity (such as
adding extra commentary) can actually obscure the code's purpose by adding
clutter, restating what the code already says, contradicting the code, or adding
maintenance burden to keep the comments up-to-date. Allow the code to speak for
itself (e.g., by making the symbol names themselves self-describing) rather than
adding redundant comments. It is often better for comments to explain why
something is done, not what the code is doing.
The Google codebase is largely uniform and consistent. It is often the case that
code that stands out (e.g., by using an unfamiliar pattern) is doing so for a
good reason, typically for performance. Maintaining this property is important
to make it clear to readers where they should focus their attention when reading
a new piece of code.
The standard library contains many examples of this principle in action. Among
them:
* Maintainer comments in
[`package sort`](https://cs.opensource.google/go/go/+/refs/tags/go1.19.2:src/sort/sort.go).
* Good
[runnable examples in the same package](https://cs.opensource.google/go/go/+/refs/tags/go1.19.2:src/sort/example_search_test.go),
which benefit both users (they
[show up in godoc](https://pkg.go.dev/sort#pkg-examples)) and maintainers
(they [run as part of tests](decisions#examples)).
* [`strings.Cut`](https://pkg.go.dev/strings#Cut) is only four lines of code,
but they improve the
[clarity and correctness of callsites](https://github.com/golang/go/issues/46336).
<a id="simplicity"></a>
### Simplicity
Your Go code should be simple for those using, reading, and maintaining it.
Go code should be written in the simplest way that accomplishes its goals, both
in terms of behavior and performance. Within the Google Go codebase, simple
code:
* Is easy to read from top to bottom
* Does not assume that you already know what it is doing
* Does not assume that you can memorize all of the preceding code
* Does not have unnecessary levels of abstraction
* Does not have names that call attention to something mundane
* Makes the propagation of values and decisions clear to the reader
* Has comments that explain why, not what, the code is doing to avoid future
deviation
* Has documentation that stands on its own
* Has useful errors and useful test failures
* May often be mutually exclusive with "clever" code
Tradeoffs can arise between code simplicity and API usage simplicity. For
example, it may be worthwhile to have the code be more complex so that the end
user of the API may more easily call the API correctly. In contrast, it may also
be worthwhile to leave a bit of extra work to the end user of the API so that
the code remains simple and easy to understand.
When code needs complexity, the complexity should be added deliberately. This is
typically necessary if additional performance is required or where there are
multiple disparate customers of a particular library or service. Complexity may
be justified, but it should come with accompanying documentation so that clients
and future maintainers are able to understand and navigate the complexity. This
should be supplemented with tests and examples that demonstrate its correct
usage, especially if there is both a "simple" and a "complex" way to use the
code.
This principle does not imply that complex code cannot or should not be written
in Go or that Go code is not allowed to be complex. We strive for a codebase
that avoids unnecessary complexity so that when complexity does appear, it
indicates that the code in question requires care to understand and maintain.
Ideally, there should be accompanying commentary that explains the rationale and
identifies the care that should be taken. This often arises when optimizing code
for performance; doing so often requires a more complex approach, like
preallocating a buffer and reusing it throughout a goroutine lifetime. When a
maintainer sees this, it should be a clue that the code in question is
performance-critical, and that should influence the care that is taken when
making future changes. If employed unnecessarily, on the other hand, this
complexity is a burden on those who need to read or change the code in the
future.
If code turns out to be very complex when its purpose should be simple, this is
often a signal to revisit the implementation to see if there is a simpler way to
accomplish the same thing.
<a id="least-mechanism"></a>
#### Least mechanism
Where there are several ways to express the same idea, prefer the one that uses
the most standard tools. Sophisticated machinery often exists, but should not be
employed without reason. It is easy to add complexity to code as needed, whereas
it is much harder to remove existing complexity after it has been found to be
unnecessary.
1. Aim to use a core language construct (for example a channel, slice, map,
loop, or struct) when sufficient for your use case.
2. If there isn't one, look for a tool within the standard library (like an
HTTP client or a template engine).
3. Finally, consider whether there is a core library in the Google codebase
that is sufficient before introducing a new dependency or creating your own.
As an example, consider production code that contains a flag bound to a variable
with a default value which must be overridden in tests. Unless intending to test
the program's command-line interface itself (say, with `os/exec`), it is simpler
and therefore preferable to override the bound value directly rather than by
using `flag.Set`.
Similarly, if a piece of code requires a set membership check, a boolean-valued
map (e.g., `map[string]bool`) often suffices. Libraries that provide set-like
types and functionality should only be used if more complicated operations are
required that are impossible or overly complicated with a map.
<a id="concision"></a>
### Concision
Concise Go code has a high signal-to-noise ratio. It is easy to discern the
relevant details, and the naming and structure guide the reader through these
details.
There are many things that can get in the way of surfacing the most salient
details at any given time:
* Repetitive code
* Extraneous syntax
* [Opaque names](#naming)
* Unnecessary abstraction
* Whitespace
Repetitive code especially obscures the differences between each
nearly-identical section, and requires a reader to visually compare similar
lines of code to find the changes. [Table-driven testing] is a good example of a
mechanism that can concisely factor out the common code from the important
details of each repetition, but the choice of which pieces to include in the
table will have an impact on how easy the table is to understand.
When considering multiple ways to structure code, it is worth considering which
way makes important details the most apparent.
Understanding and using common code constructions and idioms are also important
for maintaining a high signal-to-noise ratio. For example, the following code
block is very common in [error handling], and the reader can quickly understand
the purpose of this block.
```go
// Good:
if err := doSomething(); err != nil {
// ...
}
```
If code looks very similar to this but is subtly different, a reader may not
notice the change. In cases like this, it is worth intentionally ["boosting"]
the signal of the error check by adding a comment to call attention to it.
```go
// Good:
if err := doSomething(); err == nil { // if NO error
// ...
}
```
[Table-driven testing]: https://github.com/golang/go/wiki/TableDrivenTests
[error handling]: https://go.dev/blog/errors-are-values
["boosting"]: best-practices#signal-boost
<a id="maintainability"></a>
### Maintainability
Code is edited many more times than it is written. Readable code not only makes
sense to a reader who is trying to understand how it works, but also to the
programmer who needs to change it. Clarity is key.
Maintainable code:
* Is easy for a future programmer to modify correctly
* Has APIs that are structured so that they can grow gracefully
* Is clear about the assumptions that it makes and chooses abstractions that
map to the structure of the problem, not to the structure of the code
* Avoids unnecessary coupling and doesn't include features that are not used
* Has a comprehensive test suite to ensure promised behaviors are maintained
and important logic is correct, and the tests provide clear, actionable
diagnostics in case of failure
When using abstractions like interfaces and types which by definition remove
information from the context in which they are used, it is important to ensure
that they provide sufficient benefit. Editors and IDEs can connect directly to a
method definition and show the corresponding documentation when a concrete type
is used, but can only refer to an interface definition otherwise. Interfaces are
a powerful tool, but come with a cost, since the maintainer may need to
understand the specifics of the underlying implementation in order to correctly
use the interface, which must be explained within the interface documentation or
at the call-site.
Maintainable code also avoids hiding important details in places that are easy
to overlook. For example, in each of the following lines of code, the presence
or lack of a single character is critical to understand the line:
```go
// Bad:
// The use of = instead of := can change this line completely.
if user, err = db.UserByID(userID); err != nil {
// ...
}
```
```go
// Bad:
// The ! in the middle of this line is very easy to miss.
leap := (year%4 == 0) && (!(year%100 == 0) || (year%400 == 0))
```
Neither of these are incorrect, but both could be written in a more explicit
fashion, or could have an accompanying comment that calls attention to the
important behavior:
```go
// Good:
u, err := db.UserByID(userID)
if err != nil {
return fmt.Errorf("invalid origin user: %s", err)
}
user = u
```
```go
// Good:
// Gregorian leap years aren't just year%4 == 0.
// See https://en.wikipedia.org/wiki/Leap_year#Algorithm.
var (
leap4 = year%4 == 0
leap100 = year%100 == 0
leap400 = year%400 == 0
)
leap := leap4 && (!leap100 || leap400)
```
In the same way, a helper function that hides critical logic or an important
edge-case could make it easy for a future change to fail to account for it
properly.
Predictable names are another feature of maintainable code. A user of a package
or a maintainer of a piece of code should be able to predict the name of a
variable, method, or function in a given context. Function parameters and
receiver names for identical concepts should typically share the same name, both
to keep documentation understandable and to facilitate refactoring code with
minimal overhead.
Maintainable code minimizes its dependencies (both implicit and explicit).
Depending on fewer packages means fewer lines of code that can affect behavior.
Avoiding dependencies on internal or undocumented behavior makes code less
likely to impose a maintenance burden when those behaviors change in the future.
When considering how to structure or write code, it is worth taking the time to
think through ways in which the code may evolve over time. If a given approach
is more conducive to easier and safer future changes, that is often a good
trade-off, even if it means a slightly more complicated design.
<a id="consistency"></a>
### Consistency
Consistent code is code that looks, feels, and behaves like similar code
throughout the broader codebase, within the context of a team or package, and
even within a single file.
Consistency concerns do not override any of the principles above, but if a tie
must be broken, it is often beneficial to break it in favor of consistency.
Consistency within a package is often the most immediately important level of
consistency. It can be very jarring if the same problem is approached in
multiple ways throughout a package, or if the same concept has many names within
a file. However, even this should not override documented style principles or
global consistency.
<a id="core"></a>
## Core guidelines
These guidelines collect the most important aspects of Go style that all Go code
is expected to follow. We expect that these principles be learned and followed
by the time readability is granted. These are not expected to change frequently,
and new additions will have to clear a high bar.
The guidelines below expand on the recommendations in [Effective Go], which
provide a common baseline for Go code across the entire community.
[Effective Go]: https://go.dev/doc/effective_go
<a id="formatting"></a>
### Formatting
All Go source files must conform to the format outputted by the `gofmt` tool.
This format is enforced by a presubmit check in the Google codebase.
[Generated code] should generally also be formatted (e.g., by using
[`format.Source`]), as it is also browsable in Code Search.
[Generated code]: https://docs.bazel.build/versions/main/be/general.html#genrule
[`format.Source`]: https://pkg.go.dev/go/format#Source
<a id="mixed-caps"></a>
### MixedCaps
Go source code uses `MixedCaps` or `mixedCaps` (camel case) rather than
underscores (snake case) when writing multi-word names.
This applies even when it breaks conventions in other languages. For example, a
constant is `MaxLength` (not `MAX_LENGTH`) if exported and `maxLength` (not
`max_length`) if unexported.
Local variables are considered [unexported] for the purpose of choosing the
initial capitalization.
<!--#include file="/go/g3doc/style/includes/special-name-exception.md"-->
[unexported]: https://go.dev/ref/spec#Exported_identifiers
<a id="line-length"></a>
### Line length
There is no fixed line length for Go source code. If a line feels too long, it
should be refactored instead of broken. If it is already as short as it is
practical for it to be, the line should be allowed to remain long.
Do not split a line:
* Before an [indentation change](decisions#indentation-confusion) (e.g.,
function declaration, conditional)
* To make a long string (e.g., a URL) fit into multiple shorter lines
<a id="naming"></a>
### Naming
Naming is more art than science. In Go, names tend to be somewhat shorter than
in many other languages, but the same [general guidelines] apply. Names should:
* Not feel [repetitive](decisions#repetition) when they are used
* Take the context into consideration
* Not repeat concepts that are already clear
You can find more specific guidance on naming in [decisions](decisions#naming).
[general guidelines]: https://testing.googleblog.com/2017/10/code-health-identifiernamingpostforworl.html
<a id="local-consistency"></a>
### Local consistency
Where the style guide has nothing to say about a particular point of style,
authors are free to choose the style that they prefer, unless the code in close
proximity (usually within the same file or package, but sometimes within a team
or project directory) has taken a consistent stance on the issue.
Examples of **valid** local style considerations:
* Use of `%s` or `%v` for formatted printing of errors
* Usage of buffered channels in lieu of mutexes
Examples of **invalid** local style considerations:
* Line length restrictions for code
* Use of assertion-based testing libraries
If the local style disagrees with the style guide but the readability impact is
limited to one file, it will generally be surfaced in a code review for which a
consistent fix would be outside the scope of the CL in question. At that point,
it is appropriate to file a bug to track the fix.
If a change would worsen an existing style deviation, expose it in more API
surfaces, expand the number of files in which the deviation is present, or
introduce an actual bug, then local consistency is no longer a valid
justification for violating the style guide for new code. In these cases, it is
appropriate for the author to clean up the existing codebase in the same CL,
perform a refactor in advance of the current CL, or find an alternative that at
least does not make the local problem worse.
<!--
-->
{% endraw %}

183
go/index.md Normal file
View File

@ -0,0 +1,183 @@
# Go Style
https://google.github.io/styleguide/go
[Overview](index) | [Guide](guide) | [Decisions](decisions) |
[Best practices](best-practices)
<!--
-->
{% raw %}
<a id="about"></a>
## About
The Go Style Guide and accompanying documents codify the current best approaches
for writing readable and idiomatic Go. Adherence to the Style Guide is not
intended to be absolute, and these documents will never be exhaustive. Our
intention is to minimize the guesswork of writing readable Go so that newcomers
to the language can avoid common mistakes. The Style Guide also serves to unify
the style guidance given by anyone reviewing Go code at Google.
Document | Link | Primary Audience | [Normative] | [Canonical]
------------------- | ----------------------------------------------------- | ------------------- | ----------- | -----------
**Style Guide** | https://google.github.io/styleguide/go/guide | Everyone | Yes | Yes
**Style Decisions** | https://google.github.io/styleguide/go/decisions | Readability Mentors | Yes | No
**Best Practices** | https://google.github.io/styleguide/go/best-practices | Anyone interested | No | No
[Normative]: #normative
[Canonical]: #canonical
<a id="docs"></a>
### Documents
1. The **Style Guide** (https://google.github.io/styleguide/go/guide) outlines
the foundation of Go style at Google. This document is definitive and is
used as the basis for the recommendations in Style Decisions and Best
Practices.
1. **Style Decisions** (https://google.github.io/styleguide/go/decisions) is a
more verbose document that summarizes decisions on specific style points and
discusses the reasoning behind the decisions where appropriate.
These decisions may occasionally change based on new data, new language
features, new libraries, or emerging patterns, but it is not expected that
individual Go programmers at Google should keep up-to-date with this
document.
1. **Best Practices** (https://google.github.io/styleguide/go/best-practices)
documents some of the patterns that have evolved over time that solve common
problems, read well, and are robust to code maintenance needs.
These best practices are not canonical, but Go programmers at Google are
encouraged to use them where possible to keep the codebase uniform and
consistent.
These documents intend to:
* Agree on a set of principles for weighing alternate styles
* Codify settled matters of Go style
* Document and provide canonical examples for Go idioms
* Document the pros and cons of various style decisions
* Help minimize surprises in Go readability reviews
* Help readability mentors use consistent terminology and guidance
These documents do **not** intend to:
* Be an exhaustive list of comments that can be given in a readability review
* List all of the rules everyone is expected to remember and follow at all
times
* Replace good judgment in the use of language features and style
* Justify large-scale changes to get rid of style differences
There will always be differences from one Go programmer to another and from one
team's codebase to another. However, it is in the best interest of Google and
Alphabet that our codebase be as consistent as possible. (See
[guide](guide#consistency) for more on consistency.) To that end, feel free to
make style improvements as you see fit, but you do not need to nit-pick every
violation of the Style Guide that you find. In particular, these documents may
change over time, and that is no reason to cause extra churn in existing
codebases; it suffices to write new code using the latest best practices and
address nearby issues over time.
It is important to recognize that issues of style are inherently personal and
that there are always inherent trade-offs. Much of the guidance in these
documents is subjective, but just like with `gofmt`, there is significant value
in the uniformity they provide. As such, style recommendations will not be
changed without due discourse, Go programmers at Google are encouraged to follow
the style guide even where they might disagree.
<a id="definitions"></a>
## Definitions
The following words, which are used throughout the style documents, are defined
below:
* **Canonical**: Establishes prescriptive and enduring rules
<a id="canonical"></a>
Within these documents, "canonical" is used to describe something that is
considered a standard that all code (old and new) should follow and that is
not expected to change substantially over time. Principles in the canonical
documents should be understood by authors and reviewers alike, so everything
included within a canonical document must meet a high bar. As such,
canonical documents are generally shorter and prescribe fewer elements of
style than non-canonical documents.
https://google.github.io/styleguide/go#canonical
* **Normative**: Intended to establish consistency <a id="normative"></a>
Within these documents, "normative" is used to describe something that is an
agreed-upon element of style for use by Go code reviewers, in order that the
suggestions, terminology, and justifications are consistent. These elements
may change over time, and these documents will reflect such changes so that
reviewers can remain consistent and up-to-date. Authors of Go code are not
expected to be familiar with the normative documents, but the documents will
frequently be used as a reference by reviewers in readability reviews.
https://google.github.io/styleguide/go#normative
* **Idiomatic**: Common and familiar <a id="idiomatic"></a>
Within these documents, "idiomatic" is used to refer to something that is
prevalent in Go code and has become a familiar pattern that is easy to
recognize. In general, an idiomatic pattern should be preferred to something
unidiomatic if both serve the same purpose in context, as this is what will
be the most familiar to readers.
https://google.github.io/styleguide/go#idiomatic
<a id="references"></a>
## Additional references
This guide assumes the reader is familiar with [Effective Go], as it provides a
common baseline for Go code across the entire Go community.
Below are some additional resources for those looking to self-educate about Go
style and for reviewers looking to provide further linkable context in their
reviews. Participants in the Go readability process are not expected to be
familiar with these resources, but they may arise as context in readability
reviews.
[Effective Go]: https://go.dev/doc/effective_go
**External References**
* [Go Language Specification](https://go.dev/ref/spec)
* [Go FAQ](https://go.dev/doc/faq)
* [Go Memory Model](https://go.dev/ref/mem)
* [Go Data Structures](https://research.swtch.com/godata)
* [Go Interfaces](https://research.swtch.com/interfaces)
* [Go Proverbs](https://go-proverbs.github.io/)
* <a id="gotip"></a> Go tips - stay tuned.
**Relevant Testing-on-the-Toilet articles**
* [https://testing.googleblog.com/2017/10/code-health-identifiernamingpostforworl.html](Identifier Naming)
* [https://testing.googleblog.com/2013/03/testing-on-toilet-testing-state-vs.html](Testing State vs. Testing Interactions)
* [https://testing.googleblog.com/2014/05/testing-on-toilet-effective-testing.html](Effective Testing)
* [https://testing.googleblog.com/2014/05/testing-on-toilet-risk-driven-testing.html](Risk-driven Testing)
* [https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html](Change-detector Tests Considered Harmful)
**Additional External Writings**
* [Go and Dogma](https://research.swtch.com/dogma)
* [Less is exponentially more](https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html)
* [Esmerelda's Imagination](https://commandcenter.blogspot.com/2011/12/esmereldas-imagination.html)
* [Regular expressions for parsing](https://commandcenter.blogspot.com/2011/08/regular-expressions-in-lexing-and.html)
* [Gofmt's style is no one's favorite, yet Gofmt is everyone's favorite](https://www.youtube.com/watch?v=PAAkCSZUG1c&t=8m43s)
(YouTube)
<!--
-->
{% endraw %}