65a433d0c6
Absorbed content from rodin/golang-conventions and rodin/prometheus-conventions into a sources/ directory. Reference material — descriptive, not prescriptive. Part of taxonomy cleanup (elixir-patterns issue #4).
271 lines
8.2 KiB
Markdown
271 lines
8.2 KiB
Markdown
# Go Language Source: Convention Reference
|
|
|
|
Quick-reference for conventions extracted from the golang/go source
|
|
code. Each entry: pattern name, location, example, when to use,
|
|
when NOT to use, origin.
|
|
|
|
---
|
|
|
|
## Owner-Attributed TODOs
|
|
|
|
**Location:** Throughout `src/`
|
|
|
|
```go
|
|
// TODO(gri): consider using a different approach here
|
|
// TODO(rsc): this should be cleaned up in the next release
|
|
```
|
|
|
|
**When to use:** Known limitations that a specific person should
|
|
address. The owner tag creates accountability without creating an
|
|
issue (issues are for user-visible problems; TODOs are for internal
|
|
engineering debt).
|
|
|
|
**When NOT to use:** User-visible bugs (file an issue instead).
|
|
Aspirational improvements with no clear owner. Anything that should
|
|
block a release.
|
|
|
|
**Origin:** Convention since Go's earliest commits. The Go team
|
|
averages 3,428 TODOs across the codebase — this is a conscious
|
|
engineering culture, not neglect.
|
|
|
|
---
|
|
|
|
## `internal/` Packages
|
|
|
|
**Location:** `src/internal/` (61 packages)
|
|
|
|
```go
|
|
// internal/singleflight — dedup concurrent calls
|
|
// internal/godebug — runtime feature flags
|
|
// internal/poll — OS I/O polling
|
|
// internal/bisect — binary search debugging
|
|
```
|
|
|
|
**When to use:** Code shared between stdlib packages that should NOT
|
|
become public API. Utility code that isn't stable enough for the
|
|
compatibility promise. Implementation details that users shouldn't
|
|
depend on.
|
|
|
|
**When NOT to use:** Code that external packages need. Code that's
|
|
stable enough for public API (promote it). One-off helpers that only
|
|
one package uses (keep them package-private).
|
|
|
|
**Origin:** `src/internal/` existed since Go moved sources from
|
|
`src/pkg` to `src` (2014). The compiler enforces the import restriction
|
|
— no code outside the tree can import internal packages.
|
|
|
|
---
|
|
|
|
## GODEBUG: Runtime Feature Flags
|
|
|
|
**Location:** `internal/godebug/godebug.go` (316 lines)
|
|
|
|
```go
|
|
var http2server = godebug.New("http2server")
|
|
|
|
func ServeConn(c net.Conn) {
|
|
if http2server.Value() == "0" {
|
|
// user opted out of HTTP/2
|
|
}
|
|
// IncNonDefault must be called each time non-default behavior fires
|
|
http2server.IncNonDefault()
|
|
}
|
|
```
|
|
|
|
**When to use:** Behavior changes that might break existing programs.
|
|
The old behavior becomes accessible via `GODEBUG=setting=value`. Tied
|
|
to `go.mod`'s `go` directive for automatic version-based defaults.
|
|
|
|
**When NOT to use:** Bug fixes that no reasonable program depends on.
|
|
New features (use GOEXPERIMENT instead). Performance optimizations that
|
|
don't change observable behavior.
|
|
|
|
**Origin:** Brad Fitzpatrick added the package in Aug 2021. Russ Cox
|
|
formalized it as the backward compatibility mechanism in proposal
|
|
#56986 (Nov 2022, 70 comments). 79 settings now exist.
|
|
|
|
---
|
|
|
|
## GOEXPERIMENT: Compile-Time Feature Gates
|
|
|
|
**Location:** `internal/goexperiment/flags.go` (136 lines)
|
|
|
|
```go
|
|
// Set via: GOEXPERIMENT=jsonv2 go build
|
|
// Check via build tag: //go:build goexperiment.jsonv2
|
|
```
|
|
|
|
**When to use:** Major new APIs or behavior changes that need real-world
|
|
testing before committing to the compatibility promise. The code lives
|
|
in-tree but isn't visible without the flag.
|
|
|
|
**When NOT to use:** Small features that can ship directly. Bug fixes.
|
|
Internal refactoring. Anything that doesn't need user feedback before
|
|
committing.
|
|
|
|
**Origin:** The GOEXPERIMENT mechanism predates its formalization — used
|
|
for fieldtrack, regabi, unified. json/v2 (Apr 2025) is the highest-
|
|
profile use: 6,387 lines shipped behind a flag.
|
|
|
|
---
|
|
|
|
## Compiler Directives
|
|
|
|
**Location:** Throughout `runtime/` and `cmd/`
|
|
|
|
```go
|
|
//go:linkname localName remote/pkg.ExportedName
|
|
//go:nosplit
|
|
//go:nowritebarrier
|
|
//go:noescape
|
|
//go:systemstack
|
|
```
|
|
|
|
**When to use:** ONLY in the runtime and compiler. `linkname` accesses
|
|
unexported symbols across packages. `nosplit` prevents stack growth
|
|
checks. `nowritebarrier` asserts no GC barriers. `systemstack` forces
|
|
execution on the system stack.
|
|
|
|
**When NOT to use:** In application code. In stdlib packages outside
|
|
runtime. In third-party packages (explicitly unsupported — the Go team
|
|
actively removes `go:linkname` targets that external packages depend
|
|
on).
|
|
|
|
**Origin:** 1,711 `go:linkname` and 2,428 other runtime directives.
|
|
The Go team is actively trying to reduce linkname usage (92 touches
|
|
in 2024, many removals).
|
|
|
|
---
|
|
|
|
## Generated Code (Checked In)
|
|
|
|
**Location:** `cmd/compile/internal/ssa/`
|
|
|
|
```go
|
|
// Code generated by ssa/gen/*.go; DO NOT EDIT.
|
|
|
|
// opGen.go — 97,135 lines
|
|
// rewriteAMD64.go — 79,703 lines
|
|
// rewritegeneric.go — 38,337 lines
|
|
```
|
|
|
|
**When to use:** When the generated output needs `git blame` history.
|
|
When generators should be auditable alongside their output. When build
|
|
reproducibility matters (no external tool dependency).
|
|
|
|
**When NOT to use:** When the generated output is large AND changes
|
|
frequently (diff noise). When the generator is trivial (just use
|
|
`go generate` at build time).
|
|
|
|
**Origin:** SSA compiler introduced on dev.ssa branch (2015). The
|
|
rewrite rules are generated from a DSL but checked in so reviewers
|
|
can see exactly what changed.
|
|
|
|
---
|
|
|
|
## Assembly in Runtime
|
|
|
|
**Location:** `runtime/*.s` (200 files)
|
|
|
|
```asm
|
|
// runtime/asm_amd64.s
|
|
TEXT runtime·gogo(SB), NOSPLIT, $0-8
|
|
MOVQ buf+0(FP), BX // gobuf
|
|
MOVQ gobuf_g(BX), DX
|
|
...
|
|
```
|
|
|
|
**When to use:** Context switches, atomic operations, system calls,
|
|
and anything that needs direct control over registers/stack. Each
|
|
architecture has its own set of assembly files.
|
|
|
|
**When NOT to use:** Anything that can be written in Go with acceptable
|
|
performance. The Go team actively converts assembly to Go where
|
|
possible (e.g., crypto packages moving from asm to Go+intrinsics).
|
|
|
|
**Origin:** Runtime has always included assembly — Go's scheduler and
|
|
GC require direct hardware control that no high-level language can
|
|
provide.
|
|
|
|
---
|
|
|
|
## Proposal Process (Committee Governance)
|
|
|
|
**Location:** GitHub issues, not PRs
|
|
|
|
```
|
|
Issue #71497 (json/v2): 201 comments, Jan 2025
|
|
Issue #56986 (GODEBUG): 70 comments, Nov 2022
|
|
Issue #56345 (slog): 841 comments, 10 months
|
|
Issue #15292 (generics): 874 comments, 5 years
|
|
```
|
|
|
|
**When to use:** Any user-visible API addition or behavior change.
|
|
The proposal process ensures all edge cases are considered before
|
|
committing to the compatibility promise.
|
|
|
|
**When NOT to use:** Internal refactoring, performance improvements
|
|
that don't change API, bug fixes. These go through normal code review
|
|
(Gerrit/GitHub).
|
|
|
|
**Origin:** The Go proposal process evolved from informal (early Go)
|
|
to formalized (2015+). Russ Cox and the Go team manage a proposal
|
|
review meeting that triages and decides.
|
|
|
|
---
|
|
|
|
## The Scheduler as Documentation
|
|
|
|
**Location:** `runtime/proc.go` (8,156 lines)
|
|
|
|
```go
|
|
// Goroutine scheduler
|
|
// The scheduler's job is to distribute ready-to-run goroutines over
|
|
// worker threads.
|
|
//
|
|
// The main concepts are:
|
|
// G - goroutine.
|
|
// M - worker thread, or machine.
|
|
// P - processor, a resource that is required to execute Go code.
|
|
```
|
|
|
|
**When to use:** Complex algorithms should document their model at the
|
|
top of the file. The Go runtime uses extensive comments to explain
|
|
the scheduler's invariants, the GC's phases, and the memory
|
|
allocator's structure.
|
|
|
|
**When NOT to use:** Simple code that's self-documenting. Comments
|
|
that restate what the code does rather than WHY it does it.
|
|
|
|
**Origin:** The G-M-P model comment dates to the scheduler rewrite
|
|
(2014). The convention of architectural documentation at file-top
|
|
extends throughout the runtime.
|
|
|
|
---
|
|
|
|
## json/v2: Experiment-to-Stdlib Pipeline
|
|
|
|
**Location:** `encoding/json/v2/` (6,387 lines, 13 files)
|
|
|
|
```go
|
|
// encoding/json/v2 — semantic layer (uses reflection)
|
|
// encoding/jsontext — syntactic layer (no reflection dependency)
|
|
```
|
|
|
|
**When to use:** When building a major stdlib revision. The pattern:
|
|
1. Build as external module (`go-json-experiment/json`)
|
|
2. Iterate with real users for years
|
|
3. Propose for stdlib with working implementation
|
|
4. Ship behind GOEXPERIMENT flag
|
|
5. Graduate when stable
|
|
|
|
**When NOT to use:** Small additions that don't need years of
|
|
iteration. Features that can be backward-compatible additions to
|
|
existing packages.
|
|
|
|
**Origin:** `go-json-experiment/json` existed since 2022. Proposed as
|
|
#71497 (Jan 2025, 201 comments). Landed behind flag Apr 2025 (commit
|
|
`0e17905793` by Damien Neil).
|
|
|
|
<!-- PATTERN_COMPLETE -->
|