Files
Rodin 65a433d0c6 chore: merge golang-conventions and prometheus-conventions into sources/
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).
2026-05-07 18:02:04 -07:00

8.2 KiB

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/

// 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)

// 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)

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)

// 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: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/

// 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)

// 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)

// 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)

// 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).