diff --git a/sources/README.md b/sources/README.md new file mode 100644 index 0000000..190606a --- /dev/null +++ b/sources/README.md @@ -0,0 +1,15 @@ +# Sources + +Reference material extracted from specific projects. Study for ideas, don't copy blindly. + +These are **descriptive** — they document what a project does and why. +The `patterns/` directory is **prescriptive** — it tells you what to do. + +Patterns that prove broadly applicable get promoted from here into `patterns/`. +The rest stays as reference for understanding how mature projects solve specific problems. + +## Files + +- `golang.md` — conventions from the golang/go source +- `golang-analysis.md` — deeper analysis of golang/go source architecture +- `prometheus.md` — patterns from prometheus/prometheus (TSDB, storage, metrics) diff --git a/sources/golang-analysis.md b/sources/golang-analysis.md new file mode 100644 index 0000000..fe35e9e --- /dev/null +++ b/sources/golang-analysis.md @@ -0,0 +1,364 @@ +# Go Language Source: Architectural Conventions + +How does the Go team build Go itself? What does the language source +reveal about conventions, governance, and infrastructure decisions? + +**Repo:** [golang/go](https://github.com/golang/go) + +--- + +## 1. Repo Shape + +| Metric | Value | +|--------|-------| +| Size | 632M | +| Go files | 11,245 | +| Assembly files (runtime) | 200 | +| Commits | 66,142 | +| Contributors | 2,842 | +| Test files | 1,811 | +| Non-test files | 6,065 | +| Test ratio | 1:3.3 | +| TODOs (non-test) | 3,428 (all owner-attributed) | + +### Organizational Philosophy + +``` +src/ +├── cmd/ # The toolchain (compile, link, go, gofmt, vet) +│ └── compile/ +│ └── internal/ssa/ # 417,686 lines of SSA compiler +├── internal/ # 61 hidden packages (API firewall) +├── runtime/ # 129,141 lines (scheduler, GC, memory) +├── encoding/ # Serialization (json, xml, gob) +├── net/ # Networking +├── io/ # Stream interfaces +└── testing/ # Test framework +``` + +The Go source has three layers: +1. **Flat stdlib** — user-visible packages (`fmt`, `io`, `net`) +2. **`internal/`** — shared infrastructure hidden from users (61 packages) +3. **`cmd/`** — the toolchain itself (compiler, linker, build tool) + +--- + +## 2. What the Codebase Values + +### By import frequency + +| Package | Imports | Role | +|---------|---------|------| +| `fmt` | 2,031 | Formatting (the universal tool) | +| `testing` | 1,658 | Tests are first-class citizens | +| `strings` | 1,454 | String manipulation | +| `os` | 1,306 | System interaction | +| `unsafe` | 1,304 | Low-level memory access | +| `runtime` | 970 | Runtime introspection | +| `io` | 924 | Stream abstraction | + +**The surprise:** `unsafe` (1,304 imports) ranks 5th — nearly tied with +`os`. The language that preaches memory safety uses `unsafe` extensively +in its own implementation. This is the "know the rules so you know +where they don't apply" principle. + +### By size (what consumes the most lines) + +| Component | Lines | Nature | +|-----------|-------|--------| +| SSA compiler | 417,686 | Mostly generated rewrite rules | +| Runtime | 129,141 | Scheduler + GC + memory | +| `testing/` | 4,770 | Testing framework | +| `internal/poll` | 5,087 | OS I/O multiplexing | +| `internal/fuzz` | 4,220 | Fuzzing infrastructure | +| `encoding/json/v2` | 6,387 | The JSON rewrite (experiment) | + +--- + +## 3. The Bootstrap Problem + +**How does Go compile itself?** + +Go has been self-hosting since May 2015 (Russ Cox, commit `0f4132c907`: +"all: build and use go tool compile, go tool link"). The bootstrap +chain: + +1. A pre-built Go 1.4 binary compiles the bootstrap tools +2. Those tools compile the current Go toolchain +3. The new toolchain recompiles itself for correctness + +**The `cmd/dist` tool** orchestrates this multi-stage build. Unlike +Elixir (which keeps 33 Erlang files permanently), Go eliminated its +non-Go dependencies entirely. The only external requirement is a +previous Go binary. + +**Convention:** Self-hosting means the compiler, linker, and runtime +are all written in Go. The runtime includes 200 assembly files for +architecture-specific operations (scheduler context switches, atomic +operations, system calls). + +--- + +## 4. TODO Culture: Owned Accountability + +```go +// TODO(gri) — 320 occurrences (Robert Griesemer) +// TODO(mdempsky) — 198 occurrences (Matthew Dempsky) +// TODO(adonovan) — 170 occurrences (Alan Donovan) +// TODO(mknyszek) — 98 occurrences (Michael Knyszek) +// TODO(rsc) — 96 occurrences (Russ Cox) +``` + +**3,428 TODOs** in non-test code. Every TODO has an owner. The top 5 +TODO authors are all core team members (compiler, runtime, and tools +leads). + +**Convention:** `// TODO(username): description` + +**Growth pattern:** linkname directives — 43 touches in 2019, 48 in +2022, 92 in 2024, 72 in 2025. The codebase is actively evolving its +relationship with internal/external boundaries. + +**Contrast with Elixir:** Go TODOs are permanent documentation of known +limitations. Elixir TODOs are time-bombs with version deadlines. Go +accepts technical debt as a layer; Elixir refuses to let it accumulate. + +--- + +## 5. Unique Patterns + +### 5.1 `internal/` as API Firewall (61 packages) + +Go's most distinctive structural pattern. The `internal/` directory is +enforced by the compiler — code outside the tree cannot import these +packages. + +**Key internal packages:** +- `internal/godebug` — runtime feature flags (79 settings) +- `internal/goexperiment` — compile-time experiment guards +- `internal/singleflight` — dedup concurrent function calls +- `internal/bisect` — binary search for debugging (Russ Cox, 2023) +- `internal/poll` — OS I/O polling (5,087 lines) +- `internal/fuzz` — fuzzing coordinator (4,220 lines) +- `internal/coverage` — code coverage (3,821 lines) + +**Convention:** Code shared between stdlib packages but not suitable for +public API goes in `internal/`. This is Go's answer to "how do you +share utilities without committing to backward compatibility." + +### 5.2 GODEBUG: Runtime Feature Flags + +Introduced 2021 (Brad Fitzpatrick), formalized as a compatibility +mechanism by Russ Cox in 2022 (proposal #56986: "extended backwards +compatibility for Go", 70 comments). + +```go +var http2server = godebug.New("http2server") + +func ServeConn(c net.Conn) { + if http2server.Value() == "0" { + // disable HTTP/2 + } +} +``` + +**79 godebug settings** across the codebase. Each time a non-default +setting causes a behavior change, code calls `IncNonDefault()` to +increment a counter readable via `runtime/metrics`. + +**Convention:** When a behavior change might break existing programs, +add a GODEBUG setting. The old behavior remains accessible via +`GODEBUG=setting=old_value`. New Go versions automatically use the +old behavior when building code that declared an older `go` directive +in `go.mod`. + +**This is the Go compatibility promise made machine-enforceable.** + +### 5.3 GOEXPERIMENT: Compile-Time Feature Gates + +```go +// In internal/goexperiment/flags.go: +// GOEXPERIMENT=jsonv2 enables the new JSON API +``` + +**Convention:** Major API additions ship behind experiment flags. +`encoding/json/v2` (6,387 lines, Apr 2025) exists in the tree but is +only visible when `GOEXPERIMENT=jsonv2` is set. This allows the code +to be developed in-tree, tested by adventurous users, and refined +before the compatibility promise applies. + +### 5.4 Compiler Directives as Hidden Language + +```go +//go:linkname localFunction remote/package.Function +//go:nosplit +//go:nowritebarrier +//go:noescape +//go:systemstack +``` + +**1,711 `go:linkname` directives** and **2,428 runtime compiler +directives** in non-test code. These are effectively a hidden language +within Go — they bypass the type system, calling conventions, and +garbage collector safety for performance-critical paths. + +**Convention:** Directives are ONLY acceptable in the runtime and +compiler. The Go team is actively trying to reduce `go:linkname` usage +(92 touches in 2024 — many are removals). Third-party packages that use +`go:linkname` to access internals are explicitly unsupported. + +### 5.5 Generated Code: The SSA Compiler + +The SSA (Static Single Assignment) compiler backend is 417,686 lines, +but the largest files are generated: + +``` +opGen.go — 97,135 lines (generated) +rewriteAMD64.go — 79,703 lines (generated) +rewritegeneric.go — 38,337 lines (generated) +rewriteARM64.go — 26,203 lines (generated) +``` + +**Convention:** Generated files are checked into the repo (not +generated at build time). They contain a `// Code generated` header. +The generators live alongside their output. This means `git blame` +works on generated code — you can trace when a rewrite rule was added. + +### 5.6 The Runtime: 129K Lines of Go + Assembly + +``` +proc.go — 8,156 lines (THE goroutine scheduler) +malloc.go — 2,501 lines (memory allocator) +mgc.go — 2,315 lines (garbage collector) +mheap.go — 3,030 lines (heap management) +panic.go — 1,788 lines (panic/recover machinery) +``` + +The scheduler (`proc.go`) documents its own design at the top: +> "The main concepts are: G - goroutine. M - worker thread, or machine. +> P - processor, a resource that is required to execute Go code." + +**Convention:** The runtime combines Go and assembly (200 `.s` files). +Architecture-specific operations (context switches, atomic ops, system +calls) are in assembly. Everything else is in Go, using compiler +directives to bypass safety checks where needed. + +--- + +## 6. PR Discussion Patterns + +Go uses GitHub issues for proposals, not PRs for discussion. The key +governance mechanism is the **proposal process** with designated +reviewers. + +### json/v2 (Issue #71497, 201 comments, Jan 2025) + +"The largest major revision of a standard Go package to date." + +**Key design decision:** Split into `encoding/json/v2` (semantic) and +`encoding/jsontext` (syntactic). The syntactic layer has no reflection +dependency — it's a pure JSON tokenizer. + +**Ship strategy:** Land behind `GOEXPERIMENT=jsonv2`, iterate with +community feedback, then graduate. The code lives in-tree but doesn't +count as a compatibility commitment until the experiment flag is +removed. + +**External validation:** Built as `github.com/go-json-experiment/json` +first, iterated for years, then proposed for stdlib. The implementation +preceded the proposal. + +### GODEBUG (Issue #56986, 70 comments, Nov 2022) + +Russ Cox's proposal for machine-enforced backward compatibility. + +**The problem:** Sort algorithm changes, bug fixes, and behavior +improvements can break programs that depend on old behavior. + +**The solution:** `go.mod`'s `go` directive becomes a compatibility +declaration. Programs built with Go 1.22 but declaring `go 1.20` +automatically get Go 1.20 behavior for any setting that changed between +1.20 and 1.22. + +**Lesson:** The Go team solved "how do you improve a language without +breaking users" with a general mechanism rather than case-by-case +migration. Each new GODEBUG setting is a structured backward +compatibility opt-out. + +### Generics (Issue #15292, 874 comments, 2016-2021) + +5 years of discussion. The most debated language change in Go's history. + +**Lesson:** Committee-driven projects can take years on foundational +decisions because consensus requires addressing every edge case. Compare +to Elixir's formatter (1 hour, zero comments) — the BDFL model moves +faster but accepts more single-point-of-failure risk. + +### slog (Issue #56345, 841 comments, 2022-2023) + +Structured logging took 10 months and 841 comments to land. + +**Lesson:** Even when the need is clear and the solution is well-known, +Go's process requires exhaustive discussion. The result is usually +better (slog is well-designed), but the cost is measured in months. + +--- + +## 7. Cross-Ecosystem Comparisons + +| Aspect | Go | Elixir | +|--------|-----|--------| +| TODOs | 3,428, owner-attributed, permanent | 127, version-gated, deadlines | +| Self-hosting | Complete since 2015 | 33 Erlang files permanently | +| Feature gates | GOEXPERIMENT (compile-time) | None (ship or don't) | +| Compat mechanism | GODEBUG (79 settings) | Deprecation → removal on version | +| Governance | Committee (proposals, 874-comment threads) | BDFL (José, 1-hour merges) | +| Internal boundary | `internal/` (compiler-enforced, 61 packages) | OTP applications (convention-enforced) | +| Generated code | Checked in (97K-line files) | Compile-time (no artifacts) | +| Assembly | 200 .s files in runtime | None (delegates to Erlang/BEAM) | +| Biggest file | 97,135 lines (generated) | 7,102 lines (Kernel) | + +--- + +## 8. What This Teaches + +1. **`internal/` solves "shared but not public" at the language level.** + 61 packages that other ecosystems have to solve with conventions, + Go solves with compiler enforcement. This is why Go projects + rarely have "utils" packages that leak abstraction — the pattern + exists in the language itself. + +2. **GODEBUG is the most sophisticated backward compatibility mechanism + in any language runtime.** It makes the compatibility promise + *machine-verifiable* rather than *socially-enforced*. Programs don't + just get old behavior by default — they get it because their `go.mod` + declares what era they belong to. + +3. **GOEXPERIMENT enables fearless iteration in the stdlib.** json/v2 + can exist in-tree, be tested, be refined — all without triggering + the compatibility promise. This is "feature flags for a language." + +4. **3,428 TODOs is honest, not sloppy.** Each one has an owner. They + document known limitations rather than hiding them. Go prefers + "explicitly imperfect" over "implicitly broken." + +5. **Compiler directives are a hidden language.** 4,139 directives + (linkname + runtime pragmas) bypass Go's safety model. The Go team + accepts that the runtime needs a different language than users — + but actively restricts this power from escaping to third-party code. + +6. **Generated code checked in > generated at build time** for + archaeology. `git blame` on `rewriteAMD64.go` tells you when a + codegen rule was added and why. Build-time generation loses this + history. + +7. **Committee governance produces better designs but 10x slower.** Go's + slog (841 comments, 10 months) vs Elixir's formatter (0 comments, + 1 hour). The designs are comparable in quality — the process cost + is where they differ. + +8. **`unsafe` in Go's own source (1,304 imports) proves that safety + rules are for users, not for runtime implementors.** The people who + wrote the safety rules know exactly where they don't apply. + + diff --git a/sources/golang.md b/sources/golang.md new file mode 100644 index 0000000..c3998d0 --- /dev/null +++ b/sources/golang.md @@ -0,0 +1,270 @@ +# 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). + + diff --git a/sources/prometheus.md b/sources/prometheus.md new file mode 100644 index 0000000..6a63606 --- /dev/null +++ b/sources/prometheus.md @@ -0,0 +1,182 @@ +# Patterns Extracted from prometheus/prometheus + +## Pattern: Atomic File Operations with Suffix Convention + +**Source:** `tsdb/db.go` +**Category:** storage + +**What:** Use directory suffixes (`.tmp-for-creation`, +`.tmp-for-deletion`) to make multi-step file operations +crash-safe. On startup, clean up any dirs with these +suffixes (they represent incomplete operations). + +**Why:** Database storage needs atomicity. If the process +crashes between creating a block and finalizing it, you +need to know the block is incomplete. The suffix convention +makes incomplete state visible at the filesystem level +without requiring a separate journal. + +**Example:** + +```go +const ( + tmpForDeletionBlockDirSuffix = ".tmp-for-deletion" + tmpForCreationBlockDirSuffix = ".tmp-for-creation" +) + +// On startup: remove any .tmp-* dirs (incomplete ops) +// On create: write to dir.tmp-for-creation, then rename +// On delete: rename to dir.tmp-for-deletion, then remove +``` + +**When to use:** Any system that manages files/directories +and needs crash consistency without a full WAL. Simpler +than a write-ahead log for coarse-grained operations. + +**When NOT to use:** When you already have a WAL or +transaction log. Or for fine-grained operations where +rename semantics are insufficient. + +--- + +## Pattern: DefaultOptions() Function + +**Source:** `tsdb/db.go` +**Category:** configuration + +**What:** Provide a `DefaultOptions()` function returning a +fully-populated config struct. Users copy and override only +what they need. No nil-means-default ambiguity. + +**Why:** Large config structs (20+ fields) are unwieldy. +By providing sane defaults as a function (not a +package-level var), you avoid mutation bugs and make it +clear what "normal" looks like. Users only specify +deviations. + +**Example:** + +```go +func DefaultOptions() *Options { + return &Options{ + WALSegmentSize: wlog.DefaultSegmentSize, + RetentionDuration: int64(15*24*time.Hour / ...), + MinBlockDuration: DefaultBlockDuration, + MaxBlockDuration: DefaultBlockDuration, + SamplesPerChunk: DefaultSamplesPerChunk, + // ... 20 more fields with sane defaults + } +} + +// Usage: +opts := tsdb.DefaultOptions() +opts.RetentionDuration = 30 * 24 * time.Hour +db, err := tsdb.Open(dir, nil, nil, opts, nil) +``` + +**When to use:** Config structs with many fields where most +users want defaults. Especially when zero-value semantics +would be confusing (e.g., 0 retention = infinite? or off?). + +**When NOT to use:** Small configs (3-4 fields) where +struct literal with zero-means-default is clear enough. + +--- + +## Pattern: Scrape Loop with Aligned Timestamps + +**Source:** `scrape/scrape.go` +**Category:** concurrency + +**What:** Periodic scrape loops that align timestamps to +intervals with a small tolerance, enabling better storage +compression downstream. + +**Why:** Time-series databases compress better when +timestamps are regular. A 2ms tolerance on alignment +means scraped data aligns to the expected grid while +accommodating real-world jitter. + +**Example:** + +```go +var ScrapeTimestampTolerance = 2 * time.Millisecond +var AlignScrapeTimestamps = true + +// In scrape loop: if scrape finishes within tolerance +// of expected timestamp, snap to the grid +``` + +**When to use:** Any periodic data collection where +downstream storage benefits from timestamp regularity. +Metrics, heartbeats, polling loops. + +**When NOT to use:** Event-driven data where timestamps +must reflect actual occurrence time. Audit logs, user +actions, financial transactions. + +--- + +## Pattern: Sentinel Errors with Interface Check + +**Source:** `tsdb/db.go` +**Category:** error-handling + +**What:** Define package-level sentinel errors with +`errors.New()` and use compile-time interface assertions +to verify implementations satisfy storage interfaces. + +**Why:** `ErrNotReady` as a sentinel lets callers use +`errors.Is` for retry logic. The pattern ensures error +identity is stable across versions (not string-matched). + +**Example:** + +```go +var ErrNotReady = errors.New("TSDB not ready") + +// Callers can reliably detect this: +if errors.Is(err, tsdb.ErrNotReady) { + // Retry later — DB is still initializing +} +``` + +**When to use:** Any error that callers need to handle +programmatically (retry, fallback, special UI). Make it a +named sentinel, not a string comparison. + +**When NOT to use:** Errors that are always terminal or +always logged-and-discarded. Not every error needs a name. + +--- + +## Pattern: Compile-Time Interface Satisfaction + +**Source:** `scrape/scrape.go` +**Category:** organization + +**What:** Use `var _ Interface = (*Type)(nil)` to verify at +compile time that a type satisfies an interface, even if +the type is only used dynamically. + +**Why:** Without this, you discover missing methods only +when the type is actually used — which might be in a +rarely-exercised code path or only in production. The +compile-time check catches it immediately. + +**Example:** + +```go +var _ FailureLogger = (*logging.JSONFileLogger)(nil) +// Fails at compile time if JSONFileLogger doesn't +// implement FailureLogger +``` + +**When to use:** Any type that implements an interface +consumed dynamically (registered in a map, stored as +interface value, passed to framework code). + +**When NOT to use:** Types whose interface satisfaction is +already enforced by direct usage in the same package. + +