|
| 1 | +# Code Style Guide |
| 2 | + |
| 3 | +Go conventions for this repository — written for humans and coding agents |
| 4 | +alike. The [API style guide](api-style-guide.md) governs the proto surface; |
| 5 | +this document governs the Go code behind it. Repository layout is covered by |
| 6 | +[code layout](dev/code-layout.md). |
| 7 | + |
| 8 | +The baseline is [Effective Go](https://go.dev/doc/effective_go), the |
| 9 | +[Google Go style guide](https://google.github.io/styleguide/go/), and `gofmt`. |
| 10 | +This document records only decisions that are specific to this project. |
| 11 | + |
| 12 | +## Proto field access: check presence, don't default it |
| 13 | + |
| 14 | +Generated getters (e.g. `req.GetActor().GetName()`) return zero values when any |
| 15 | +message in the chain is nil. That is convenient and dangerous: a required |
| 16 | +message the caller forgot to set silently becomes `""`, and the bug surfaces |
| 17 | +far from its cause. |
| 18 | + |
| 19 | +- A getter chain must never stand in for a presence check. Whenever a field |
| 20 | + is required at this point in the code, check it explicitly and fail loudly: |
| 21 | + `INVALID_ARGUMENT` at the API boundary, a real error (not a guessed zero |
| 22 | + value) elsewhere. |
| 23 | +- Once the boundary has validated presence, getters downstream are fine, as is |
| 24 | + the guarded form for optional messages: |
| 25 | + |
| 26 | + ```go |
| 27 | + if wass := worker.Assignment; wass != nil { |
| 28 | + // Fields of wass were validated on write; use them directly. |
| 29 | + } |
| 30 | + ``` |
| 31 | + |
| 32 | +- Absence of a group of fields that are set and cleared together is |
| 33 | + represented by a nil message (`worker.Assignment == nil`), never by probing |
| 34 | + a scalar field inside it for its zero value. |
| 35 | + |
| 36 | +## Testing |
| 37 | + |
| 38 | +- Standard library `testing` only — no assertion or mocking frameworks. |
| 39 | +- Table-driven tests with `t.Run` subtests are the default shape. |
| 40 | +- Prefer a real fake when one exists: `miniredis` for the store, `envtest` for |
| 41 | + the Kubernetes API. Release |
| 42 | + resources with `t.Cleanup`. |
| 43 | + |
| 44 | +## TODOs |
| 45 | + |
| 46 | +Deferred decisions are recorded in code as `TODO(username): ...`, placed where |
| 47 | +the decision will eventually have to be made. |
0 commit comments