diff --git a/go/best-practices.md b/go/best-practices.md index 2e8457b..1ce2a40 100644 --- a/go/best-practices.md +++ b/go/best-practices.md @@ -387,12 +387,11 @@ import "path/to/creditcardtest" func TestProcessor(t *testing.T) { var spyCC creditcardtest.Spy - proc := &Processor{CC: spyCC} // declarations omitted: card and amount if err := proc.Process(card, amount); err != nil { - t.Errorf("proc.Process(card, amount) = %v, want %v", got, want) + t.Errorf("proc.Process(card, amount) = %v, want nil", err) } charges := []creditcardtest.Charge{ @@ -420,7 +419,7 @@ func TestProcessor(t *testing.T) { // declarations omitted: card and amount if err := proc.Process(card, amount); err != nil { - t.Errorf("proc.Process(card, amount) = %v, want %v", got, want) + t.Errorf("proc.Process(card, amount) = %v, want nil", err) } charges := []creditcardtest.Charge{ @@ -1223,8 +1222,9 @@ func answer(i int) string { ``` [Do not call `log` functions before flags have been parsed.](https://pkg.go.dev/github.com/golang/glog#pkg-overview) -If you must die in an `init` func, a panic is acceptable in place of the logging -call. +If you must die in a package initialization function (an `init` or a +["must" function](decisions#must-functions)), a panic is acceptable in place of +the fatal logging call. @@ -1723,7 +1723,7 @@ var i = 42 -### Non-pointer zero values +### Declaring variables with zero values The following declarations use the [zero value]: @@ -1760,6 +1760,15 @@ var coords Point if err := json.Unmarshal(data, &coords); err != nil { ``` +It is also okay to use the zero value in the following form when you need a +variable of a pointer type: + +```go +// Good: +msg := new(pb.Bar) // or "&pb.Bar{}" +if err := proto.Unmarshal(data, msg); err != nil { +``` + If you need a lock or other field that [must not be copied](decisions#copying) in your struct, you can make it a value type to take advantage of zero value initialization. It does mean that the containing type must now be passed via a @@ -1792,7 +1801,7 @@ func NewCounter(name string) *Counter { return c } -var myMsg = new(pb.Bar) // or "&pb.Bar{}". +var msg = new(pb.Bar) // or "&pb.Bar{}". ``` This is because `*pb.Something` satisfies [`proto.Message`] while `pb.Something` @@ -1806,7 +1815,7 @@ func NewCounter(name string) *Counter { return &c } -var myMsg = pb.Bar{} +var msg = pb.Bar{} ``` [`proto.Message`]: https://pkg.go.dev/google.golang.org/protobuf/proto#Message diff --git a/go/decisions.md b/go/decisions.md index 1968b56..470868b 100644 --- a/go/decisions.md +++ b/go/decisions.md @@ -195,8 +195,8 @@ const ( Words in names that are initialisms or acronyms (e.g., `URL` and `NATO`) should have the same case. `URL` should appear as `URL` or `url` (as in `urlPony`, or -`URLPony`), never as `Url`. This also applies to `ID` when it is short for -"identifier"; write `appID` instead of `appId`. +`URLPony`), never as `Url`. As a general rule, identifiers (e.g., `ID` and `DB`) +should also be capitalized similar to their usage in English prose. * In names with multiple initialisms (e.g. `XMLAPI` because it contains `XML` and `API`), each letter within a given initialism should have the same case, @@ -211,7 +211,7 @@ have the same case. `URL` should appear as `URL` or `url` (as in `urlPony`, or -Initialism(s) | Scope | Correct | Incorrect +English Usage | Scope | Correct | Incorrect ------------- | ---------- | -------- | -------------------------------------- XML API | Exported | `XMLAPI` | `XmlApi`, `XMLApi`, `XmlAPI`, `XMLapi` XML API | Unexported | `xmlAPI` | `xmlapi`, `xmlApi` @@ -221,6 +221,11 @@ gRPC | Exported | `GRPC` | `Grpc` gRPC | Unexported | `gRPC` | `grpc` DDoS | Exported | `DDoS` | `DDOS`, `Ddos` DDoS | Unexported | `ddos` | `dDoS`, `dDOS` +ID | Exported | `ID` | `Id` +ID | Unexported | `id` | `iD` +DB | Exported | `DB` | `Db` +DB | Unexported | `db` | `dB` +Txn | Exported | `Txn` | `TXN` @@ -1779,7 +1784,7 @@ canvas.RenderCube(cube, ``` Note that the lines in the above example are not wrapped at a specific column -boundary but are grouped based on co-ordinate triples. +boundary but are grouped based on coordinate triples. Long string literals within functions should not be broken for the sake of line length. For functions that include such strings, a line break can be added after @@ -2043,6 +2048,8 @@ For errors that indicate "impossible" conditions, namely bugs that should always be caught during code review and/or testing, a function may reasonably return an error or call [`log.Fatal`]. +Also see [when panic is acceptable](best-practices.md#when-to-panic). + **Note:** `log.Fatalf` is not the standard library log. See [#logging]. [Effective Go section on errors]: http://golang.org/doc/effective_go.html#errors @@ -2176,12 +2183,18 @@ clear. It is conventionally managed with a `context.Context`: ```go // Good: func (w *Worker) Run(ctx context.Context) error { + var wg sync.WaitGroup // ... for item := range w.q { // process returns at latest when the context is cancelled. - go process(ctx, item) + wg.Add(1) + go func() { + defer wg.Done() + process(ctx, item) + }() } // ... + wg.Wait() // Prevent spawned goroutines from outliving this function. } ``` @@ -2222,12 +2235,14 @@ See also: * Rethinking Classical Concurrency Patterns: [slides][rethinking-slides], [video][rethinking-video] * [When Go programs end] +* [Documentation Conventions: Contexts] [synchronous functions]: #synchronous-functions [cheney-stop]: https://dave.cheney.net/2016/12/22/never-start-a-goroutine-without-knowing-how-it-will-stop [rethinking-slides]: https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view [rethinking-video]: https://www.youtube.com/watch?v=5zXAHh5tJqQ [When Go programs end]: https://changelog.com/gotime/165 +[Documentation Conventions: Contexts]: best-practices.md#documentation-conventions-contexts @@ -2737,7 +2752,7 @@ formatting to do. See also: * Best practices on [logging errors](best-practices#error-logging) and - [custom verbosily levels](best-practices#vlog) + [custom verbosity levels](best-practices#vlog) * When and how to use the log package to [stop the program](best-practices#checks-and-panics)