|  | # Go Rubric | 
|  |  | 
|  | [TOC] | 
|  |  | 
|  | This document lists conventions to follow when writing Go in the Fuchsia Source | 
|  | Tree. These conventions are a combination of best practices, project | 
|  | preferences, and some choices made for the sake of consistency. | 
|  |  | 
|  | The conventions described here can be considered as adding or amending common | 
|  | best practices as detailed in [Effective Go] and [Go Code Review Comments]. | 
|  |  | 
|  | ## General | 
|  |  | 
|  | ### Ordering of declarations in a file | 
|  |  | 
|  | How declarations are organized within a Go file varies considerably, especially | 
|  | since it is frequent to have one large file with all-the-things, or many smaller | 
|  | files with each a-thing. We provide a few rules of thumb here. | 
|  |  | 
|  | For ordering of top-level declarations (constants, interfaces, types along with | 
|  | their associated methods), it is common to list by group of functionality, with | 
|  | the following order in each group: | 
|  |  | 
|  | * Constants (which includes enumerations); | 
|  | * Exported interfaces, types, and functions; | 
|  | * Unexported interfaces, types, and functions in support of the exported types. | 
|  |  | 
|  | As an example, a group of functionality in fidlgen lib may be the handling of | 
|  | names, while another group may be reading and denormalizing the JSON IR. Such | 
|  | groupings are good candidates to become their own separate files as they grow. | 
|  |  | 
|  | For a type with methods, it is common to list in order: | 
|  |  | 
|  | * The type declaration (e.g. `type myImpl struct { ...`); | 
|  | * The [type assertion(s)](#type-assertions), if any; | 
|  | * Methods, with exported methods first, and unexported methods second; | 
|  | * It is best to group methods implementing an interface if applicable, i.e. all | 
|  | methods for interface `Foo`, then all methods for interface `Bar`; | 
|  | * Often, despite being exported, the `String()` method will be last. | 
|  |  | 
|  | For an enumeration, see how to [define an enum](#enum). | 
|  |  | 
|  | ### Naming convention | 
|  |  | 
|  | Go is quite opinionated about how to name things. Some conventions: | 
|  |  | 
|  | * `var err error` | 
|  | * `var buf bytes.Buffer` | 
|  | * `var buf strings.Builder` | 
|  | * `var mu sync.Mutex` | 
|  | * `var wg sync.WaitGroup` | 
|  | * `var ctx context.Context` | 
|  | * `_, ok := someMap[someKey]` | 
|  | * `_, ok := someValue.(someType)` | 
|  |  | 
|  | When defining methods, ensure that the name of the receiver is consistent (when | 
|  | present). See also [pointers vs values](#pointers-vs-values). | 
|  |  | 
|  | ### Avoid exporting | 
|  |  | 
|  | In Go, identifiers can be unexported or exported (the public/private terminology | 
|  | is not used). An exported declaration starts with a capital letter | 
|  | `MyImportantThing`, while an unexported declaration starts with a lowercase | 
|  | letter `myLocalThing`. | 
|  |  | 
|  | Only export things you really need, and that you intend to reuse. Keep in mind | 
|  | that exporting in a follow up change is relatively easy so prefer to not export | 
|  | until necessary. This keeps the documentation cleaner. | 
|  |  | 
|  | If your type will be used by reflection, e.g. within templates or automatic | 
|  | diffing à la [go-cmp], you can have an unexported identifier with exported | 
|  | fields. Again, prefer unexported fields except in the situation where you are | 
|  | forced to do otherwise. | 
|  |  | 
|  | There is nothing wrong with a local variable having the same name as a type. If | 
|  | you would write `server := Server{...}` for an exported type, then `server := | 
|  | server{...}` is fine for an unexported type. | 
|  |  | 
|  | ### Never use named return values | 
|  |  | 
|  | Semantics are confusing, and error prone. Even if it might be a good usage at | 
|  | some point (rare, and doubtful), evolutions typically cause this not to be the | 
|  | case anymore, which then introduces a diff that is larger than the actual | 
|  | change. | 
|  |  | 
|  | You'll see advice saying that "it's fine to use named return values for this | 
|  | special case", or "that special case is perfect for named return values". Our | 
|  | rule is simpler, never use named return values. | 
|  |  | 
|  | (When defining interfaces, it is fine to name things. This is different from | 
|  | named returns in implementations, it has no semantic implications.) | 
|  |  | 
|  | ### Defining an enum {#enum} | 
|  |  | 
|  | The standard pattern to define an enumeration is: | 
|  |  | 
|  | ```go | 
|  | type myEnumType int | 
|  |  | 
|  | const ( | 
|  | _ myEnumType = iota | 
|  | myFirstEnumValue | 
|  | mySecondEnumValue | 
|  | ) | 
|  | ``` | 
|  |  | 
|  | The type can only be elided when using `iota`. With an explicit value, you must | 
|  | repeat the type: | 
|  |  | 
|  | ```go | 
|  | const ( | 
|  | _ myEnumType = iota | 
|  | myFirstEnumValue | 
|  | mySecondEnumValue | 
|  | // ... | 
|  | myCombinedValue myEnumType = 100 | 
|  | ) | 
|  | ``` | 
|  |  | 
|  | Additionally, if you want this enum to have a textual representation: | 
|  |  | 
|  | ```go | 
|  | var myEnumTypeStrings = map[myEnumType]string{ | 
|  | myFirstEnumValue:  "myFirstEnumValue", | 
|  | mySecondEnumValue: "mySecondEnumValue", | 
|  | } | 
|  |  | 
|  | func (val myEnumType) String() string { | 
|  | if fmt, ok := myEnumTypeStrings[val]; ok { | 
|  | return fmt | 
|  | } | 
|  | return fmt.Sprintf("myEnumType(%d)", val) | 
|  | } | 
|  | ``` | 
|  |  | 
|  | For instance [mdlint: | 
|  | TokenKind](https://cs.opensource.google/search?q=%22type%20TokenKind%20int%22&ss=fuchsia%2Ffuchsia). | 
|  | Using a `map` is preferred over using a `switch` since it is very common to | 
|  | evolve the code to compute things off of the map, e.g. a `FromString` | 
|  | constructor (inefficiently by searching, or by pre-computing a `stringsToMyEnum` | 
|  | reverse map). | 
|  |  | 
|  | You should only use an enum member with value `0` if it is a natural default. | 
|  | For more details, see the [enum FIDL API Rubric entry][enum-fidl-rubric]. | 
|  |  | 
|  | Another option is to use [`cmd/stringer`] to generate enumerations. This generates | 
|  | more efficient code, but requires a little more effort to maintain. You can use | 
|  | this approach when the enumeration has stabilized. | 
|  |  | 
|  | Note: Switching to `stringer` as the default recommended approached is tracked | 
|  | as [fxbug.dev/73539](https://fxbug.dev/73539). | 
|  |  | 
|  | ### Sets | 
|  |  | 
|  | To represent a set, use map to an empty struct: | 
|  |  | 
|  | ```go | 
|  | allMembers := map[uint32]struct{}{ | 
|  | 5: {}, | 
|  | 8: {}, | 
|  | } | 
|  | ``` | 
|  |  | 
|  | Note: It is common to see sets defined as maps to `bool` (it is what [Effective | 
|  | Go] recommends). In Fuchsia, we have chosen to always use an empty struct due to | 
|  | the small performance improvement (which comes at the cost of small added | 
|  | syntax). | 
|  |  | 
|  | ### Instantiating slices | 
|  |  | 
|  | If you're going to define the slice using a literal, then `[]T{ ... }` is the | 
|  | way to go. | 
|  |  | 
|  | Otherwise use `var slice []T` to create an empty slice, i.e. do not use | 
|  | `slice:= []T{}`. | 
|  |  | 
|  | Note that pre-allocating slices can bring meaningful performance improvements, | 
|  | and may be preferred over a simpler syntax. See for instance [slices usage and | 
|  | internals](https://go.dev/blog/slices-intro). | 
|  |  | 
|  | ### Instantiating maps | 
|  |  | 
|  | If you're going to define the map using a literal, then `map[K]T{ ... }` is the | 
|  | way to go. | 
|  |  | 
|  | Otherwise use `make(map[string]struct{})` to create an empty map, i.e. do not | 
|  | use `myEmptyMap := map[K]T{}`. | 
|  |  | 
|  | ### Non-normal returns | 
|  |  | 
|  | When an function needs to communicate a non-normal return, i.e. a 'failure', there are a few patterns: | 
|  |  | 
|  | 1. `func doSomething(...) (data, bool)`, i.e. either return the data, or false. | 
|  | 2. `func doSomething(...) *data`, i.e. either return the data, or nil. | 
|  | 3. `func doSomething(...) (data, error)`, i.e. either return the data, or an | 
|  | error. | 
|  | 4. `func doSomething(...) dataWrapper`, i.e. return a wrapper which carries | 
|  | structured information about the result of the operation. | 
|  |  | 
|  | Giving hard and fast rules for when to use which-flavor-where is not possible, | 
|  | but there are some general principles that apply. | 
|  |  | 
|  | Relying on `nil` vs present is error prone in Go when used in polymorphic | 
|  | contexts: `nil` is not a unit, there are [many `nil` and they do not equal each | 
|  | other](https://play.golang.org/p/RvxsIbQ3NLH)! Therefore, prefer returning an | 
|  | extra `ok` boolean when uses of the method will likely be in polymorphic | 
|  | contexts. Only use `nil` vs present as an indication when the method will be | 
|  | used solely in monomorphic contexts. Or said another way, using pattern (2) is | 
|  | simpler than (1) and a good replacement when all callers will be using the | 
|  | function without looking at the returned value through the lens of an interface. | 
|  |  | 
|  | Returning an `error` indicates that something problematic occurred, the caller | 
|  | is provided with an explanation for what happened. It is expected for the caller | 
|  | to bubble up the error, possibly wrapping it along the way, or do some sort of | 
|  | error handling and recovery. A key distinction from a method returning an `ok` | 
|  | boolean (or `nil` data), is that when returning an `error` the method is | 
|  | asserting that it knows enough of the context to classify what is happening as | 
|  | erroneous. | 
|  |  | 
|  | For instance, a `LookupUser(user_id uint64)` would favor returning an ok boolean | 
|  | if no user was found, but a `LookupCountryCode(code IsoCountryCode)` would favor | 
|  | returning an `error` to identify that something is misconfigured if a country | 
|  | cannot be lookup up (or an invalid country was requested). | 
|  |  | 
|  | Returning some sort of wrapper should be considered in cases where the result of | 
|  | a method is complex, and requires structured data to describe. For instance, a | 
|  | natural candidate to use a data wrapper is a validation API which traverses an | 
|  | XML document, and returns a list of faulty paths, each with warnings or errors | 
|  | attached to them. | 
|  |  | 
|  | ### Static type assertions {#type-assertions} | 
|  |  | 
|  | Since Go uses structural subtyping, i.e. whether a type implements an interface | 
|  | is determined by its structure (not by a declaration). It is easy to think a | 
|  | type implements some interface, when in fact it does not. This results in | 
|  | breakage at a distance, at the use site, and makes for confusing compiler | 
|  | errors. | 
|  |  | 
|  | To remedy this, it is required to write type assertions for all interfaces a | 
|  | type implements (yes, those in the standard library | 
|  | [too](https://cs.opensource.google/fuchsia/fuchsia/+/main:tools/fidl/lib/fidlgen/formatter.go;drc=e67febe6dbde880bf9632fbe0540cf9251dcfd0a;l=55)): | 
|  |  | 
|  | ```go | 
|  | var _ MyInterface = (*myImplementation)(nil) | 
|  | ``` | 
|  |  | 
|  | This creates a typed nil, whose assignment forces the compiler to check for type | 
|  | conformance. | 
|  |  | 
|  | Often, we have many implementations which have to implement the same interface, | 
|  | e.g. representing an abstract syntax tree with individual nodes all implementing | 
|  | the Expression interface. In these cases, you should do all type assertions at | 
|  | once thus also documenting all subtypes which are expected: | 
|  |  | 
|  | ```go | 
|  | var _ = []MyInterface{ | 
|  | (*myImplementation)(nil), | 
|  | (*myOtherImplementation)(nil), | 
|  | ... | 
|  | } | 
|  | ``` | 
|  |  | 
|  | A rule of thumb about where these type assertions should be placed is as | 
|  | follows: | 
|  |  | 
|  | * Prefer having a single type assertion below the implementation when each | 
|  | implementation stands on its own, e.g. | 
|  | [here](https://cs.opensource.google/fuchsia/fuchsia/+/main:tools/mdlint/rules/bad_lists.go;drc=b9496c021b59ccfed5eeeaeacee5fb9dc14005a7;l=26); | 
|  | * Prefer a grouped type assertion below the interface when all implementations | 
|  | are meant to be used in concert (e.g. expression nodes of an `Expression` | 
|  | interface representing an AST), e.g. | 
|  | [here](https://cs.opensource.google/fuchsia/fuchsia/+/main:tools/fidl/lib/summarize/summary.go;drc=41966aa0f0d465f663b1b9928e5c57cf80fe38ef;l=35). | 
|  |  | 
|  | ### Embedding | 
|  |  | 
|  | Embedding is a very powerful concept in Go. Make use of it. Read | 
|  | [Embedding][Effective Go embedding] for an introduction. | 
|  |  | 
|  | When embedding an interface or a struct type, these should be listed first in | 
|  | their enclosing interface or struct type, i.e. the embedded type(s) should | 
|  | appear as the first field(s). | 
|  |  | 
|  | ### Pointers vs Values {#pointers-vs-values} | 
|  |  | 
|  | For method receivers, read [Pointers vs. Values][Effective Go pointers_vs_values] | 
|  | and [Receiver Type][Go Code Review Comments receiver-type]. | 
|  | tl;dr is to keep things consistent, but when in doubt, use a pointer receiver. | 
|  | For a given type, always be consistent about how it is passed around, i.e. | 
|  | always pass by value, always pass by reference, and this flows from whether | 
|  | methods are defined on this type (with value or pointer receiver). | 
|  |  | 
|  | It is also worth noting that passing a struct by value, thinking that the caller | 
|  | will not mutate it, is incorrect. You can easily hold maps, slices, or | 
|  | references to objects, and therefore mutate those. So in Go it's an incorrect | 
|  | association to think "pass by value is const". | 
|  |  | 
|  | Refer to [implementing interfaces](#implementing-interfaces) for specific advice | 
|  | about method receivers. | 
|  |  | 
|  | ### Implementing interfaces {#implementing-interfaces} | 
|  |  | 
|  | Generally implement interfaces using a pointer receiver; implementing an interface | 
|  | using a value receiver causes that interface to be implemented by both value and | 
|  | pointer, which complicates type assertions that attempt to enumerate possible | 
|  | implementations of an interface. See for instance | 
|  | [fxrev.dev/269371](https://fxrev.dev/269371). | 
|  |  | 
|  | There are some specific cases where implementing an interface using a value | 
|  | receiver is appropriate: | 
|  |  | 
|  | * When the type is never used as a pointer. For example, custom sorting is often | 
|  | done by defining `type mySlice []myElement` and implementing | 
|  | [`sort.Interface`](https://golang.org/pkg/sort/#Interface) on `mySlice`. The | 
|  | type `*mySlice` would never be used because `[]myElement` is already a | 
|  | reference. Example | 
|  | [here](https://cs.opensource.google/fuchsia/fuchsia/+/main:tools/mdlint/core/reporter.go?q=%22type%20sortableMessages%20%5B%5Dmessage%22). | 
|  | * When it is never expected to use a type assertion or type switch on values of | 
|  | the interface type. For example, | 
|  | [`Stringer`](https://golang.org/pkg/fmt/#Stringer) is often implemented on | 
|  | value types. It would be unusual for a function accepting `val Stringer` to | 
|  | switch on `val.(type)`. | 
|  |  | 
|  | When in doubt, always implement interfaces using a pointer receiver. | 
|  |  | 
|  | ### Comments | 
|  |  | 
|  | Read [Commentary][Effective Go commentary], in particular: | 
|  |  | 
|  | > Doc comments work best as complete 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. | 
|  |  | 
|  | ```go | 
|  | // Compile parses a regular expression and returns, if successful, | 
|  | // a Regexp that can be used to match against text. | 
|  | func Compile(str string) (*Regexp, error) { | 
|  | ``` | 
|  |  | 
|  | Doc comments on types [may have a leading | 
|  | article](https://github.com/golang/lint/blob/738671d3881b9731cc63024d5d88cf28db875626/lint.go#L832) | 
|  | "A", "An", or "The". All documentation in the Go standard library follows this | 
|  | practice, [e.g.](https://golang.org/pkg/bytes/#Buffer) `// A Buffer is a | 
|  | variable-sized ...`. | 
|  |  | 
|  | For comments which are more than a sentence long, the style generally prefers | 
|  | one summary sentence, then an empty line, then a paragraph providing further | 
|  | details. See for instance the | 
|  | [FileHeader](https://golang.org/pkg/archive/zip/#FileHeader) struct. | 
|  |  | 
|  | ### Error wrapping {#error-wrapping} | 
|  |  | 
|  | When propagating errors using `fmt.Errorf`: | 
|  |  | 
|  | * Use `%s` to only include their string values; | 
|  | * Use `%w` to allow callers to unwrap and observe wrapped errors; note `%w` | 
|  | makes those wrapped errors part of your API. | 
|  |  | 
|  | See [Working with Errors in Go | 
|  | 1.13](https://blog.golang.org/go1.13-errors), and more specifically [Whether | 
|  | to Wrap](https://blog.golang.org/go1.13-errors#TOC_3.4.). | 
|  |  | 
|  | There are some specific cases where error propagation must be done in a way that | 
|  | satisfies an API contract, e.g. often the case in a RDBMS driver where specific | 
|  | error codes returned indicate situations callers may recover from. In such | 
|  | cases, it is necessary to specifically wrap underlying errors rather than rely | 
|  | on `fmt.Errorf`. | 
|  |  | 
|  | ### `fmt` verbs | 
|  |  | 
|  | Avoid `%v` when possible, preferring specific fmt verbs that are supported by | 
|  | the operand. This has the benefit of allowing `go vet` to check that the verb is | 
|  | indeed supported by the operand. | 
|  |  | 
|  | In cases where the operand is a struct that doesn't implement `fmt.Stringer`, | 
|  | `%v` is unlikely to produce a good result anyhow; `%+v` or `%#v` are likely much | 
|  | better choices. | 
|  |  | 
|  | A common exception to this rule is an operand that may be `nil` at run-time - | 
|  | `nil` values are well handled by `%v` but not all other verbs. | 
|  |  | 
|  | When quoting strings, use `%q` instead of explicitly calling `strconv.Quote`. | 
|  |  | 
|  | When propagating errors, see [error wrapping](#error-wrapping). | 
|  |  | 
|  | ### GN targets | 
|  |  | 
|  | A typical `BUILD.gn` file for a Go tool will look something like this: | 
|  |  | 
|  | ```gn | 
|  | go_library("gopkg") { | 
|  | sources = [ | 
|  | "main.go", | 
|  | "main_test.go", | 
|  | ] | 
|  | } | 
|  |  | 
|  | go_binary("foo") { | 
|  | library = ":gopkg" | 
|  | } | 
|  |  | 
|  | go_test("foo_test") { | 
|  | library = ":gopkg" | 
|  | } | 
|  | ``` | 
|  |  | 
|  | If you have nested packages (and [only in this | 
|  | case](https://fuchsia-review.googlesource.com/c/fuchsia/+/406682/)), use | 
|  | `name = "go.fuchsia.dev/fuchsia/<path>/..."` form in go_library to enable | 
|  | recursive package sources: | 
|  |  | 
|  | ```gn | 
|  | go_library("gopkg") { | 
|  | name = "go.fuchsia.dev/fuchsia/tools/foo/..." | 
|  | sources = [ | 
|  | "main.go", | 
|  | "subdir/bar.go", | 
|  | "extra/baz.go", | 
|  | ] | 
|  | } | 
|  | ``` | 
|  |  | 
|  | Note: We are moving away from allowing `...` in `go_library` altogether, | 
|  | reserving this form for third-party code which we want to purposefully view as a | 
|  | black box. However, it is frequent for code to be decomposed into multiple | 
|  | packages, without individual packages being deemed "library quality", i.e. in a | 
|  | shape to be reused at will. We plan to update the various GN templates to | 
|  | reflect these subtleties, and offer a `go_private_library` template allowed to | 
|  | be used solely by a single `go_binary` rule, and `go_third_party_library` which | 
|  | would be the only allowing the use `...`. This is tracked as | 
|  | [fxbug.dev/73815](https://fxbug.dev/73815). | 
|  |  | 
|  | ## Testing | 
|  |  | 
|  | ### Packages ending in _test | 
|  |  | 
|  | Usually a `_test.go` file is in the same package as the code it tests (e.g. | 
|  | `package foo`), and it can access unexported declarations. [Go also allows | 
|  | you](https://tip.golang.org/cmd/go/#hdr-Test_packages) to suffix the package | 
|  | name with `_test` (e.g. `package foo_test`), in which case it is compiled as a | 
|  | separate package, but linked and run with the main binary. This approach is | 
|  | called external testing, as opposed to internal testing. Do not name a package | 
|  | with the `_test` suffix unless you are writing external tests, see instead | 
|  | [testing package](#testing-packages). | 
|  |  | 
|  | Prefer external tests when doing integration level testing, or to interact with | 
|  | the exported only portion of a package under test. | 
|  |  | 
|  | Using packages ending in `_test` is also interesting to provide compiled example | 
|  | code, which is copy pastable as-is with the package selector. For instance | 
|  | [example | 
|  | code](https://pkg.go.dev/github.com/maruel/panicparse/v2/stack#example-package-Simple) | 
|  | and [its | 
|  | source](https://github.com/maruel/panicparse/blob/master/stack/example_test.go#L161). | 
|  |  | 
|  | ### Test utilities | 
|  |  | 
|  | Testing utilities are helpers used within a package, to help with testing. It is | 
|  | 'testing code' in that it lives in a file with a `_test.go` suffix. Place | 
|  | testing utilities in a file named `testutils_test.go` file; this convention is | 
|  | interpreted by the compiler such that this code is not included in non-test | 
|  | binaries, which ensures it isn't used outside of tests. | 
|  |  | 
|  | ### Testing packages {#testing-packages} | 
|  |  | 
|  | A testing package is a library whose focus is to make writing tests easier. It | 
|  | is 'production code' — does not end in `_test.go` suffix — but intended only to | 
|  | be used from test code. | 
|  |  | 
|  | The naming convention for testing packages is to use a "test" suffix with the | 
|  | package name it is used to test. Examples in the standard library are | 
|  | [httptest](https://golang.org/pkg/net/http/httptest/) and | 
|  | [iotest](https://golang.org/pkg/testing/iotest/), in the Fuchsia tree | 
|  | [fidlgentest](/tools/fidl/lib/fidlgentest/), and | 
|  | [emulatortest](/tools/emulator/emulatortest). | 
|  |  | 
|  | ## Additional resources | 
|  |  | 
|  | * [Effective Go] | 
|  | * [Go Code Review Comments], view this as a supplement to [Effective Go] | 
|  | * [Go FAQ](https://golang.org/doc/faq) | 
|  | * [golint](https://pkg.go.dev/golang.org/x/lint/golint) | 
|  | * [Go at Google: Language Design in the Service of Software | 
|  | Engineering](https://talks.golang.org/2012/splash.article) | 
|  |  | 
|  | <!-- link labels --> | 
|  |  | 
|  | [`cmd/stringer`]: https://pkg.go.dev/golang.org/x/tools/cmd/stringer | 
|  | [Effective Go commentary]: https://golang.org/doc/effective_go#commentary | 
|  | [Effective Go embedding]: https://golang.org/doc/effective_go#embedding | 
|  | [Effective Go pointers_vs_values]: https://golang.org/doc/effective_go#pointers_vs_values | 
|  | [Effective Go]: https://golang.org/doc/effective_go | 
|  | [enum-fidl-rubric]: /docs/development/api/fidl.md#enum | 
|  | [Go Code Review Comments receiver-type]: https://github.com/golang/go/wiki/CodeReviewComments#receiver-type | 
|  | [Go Code Review Comments]: https://github.com/golang/go/wiki/CodeReviewComments | 
|  | [go-cmp]: https://github.com/google/go-cmp |