Files
atelier/languages/go.md
T
Jon Chery 4e433158cd docs(P03): complete language-derived extension — v0.4
---ci---
project: atelier
phase: 3
milestone: v0.4
status: complete
phase_role: execution
phase_tag: v0.3.3
requirements:
  covered: [ATELIER-102, ATELIER-103, ATELIER-104, ATELIER-105]
  partial: []
---/ci---
2026-08-05 16:07:21 +00:00

89 lines
3.4 KiB
Markdown

# Go — Language Application
> How Atelier's domain principles apply in Go specifically. Derives from `domains/` docs.
## Derived Docs
- [go-types.md](go-types.md) — named types, generics, interfaces, type assertion discipline.
- [go-tooling.md](go-tooling.md) — go vet, golangci-lint, go test -race, module discipline.
- [go-concurrency.md](go-concurrency.md) — goroutines, channels, context, select, sync primitives.
- [go-testing.md](go-testing.md) — table-driven tests, t.Parallel, t.Cleanup, race detector.
## Type System (C1 Correctness, Data P7 Type Fidelity)
- **Named types for domain concepts:** `type UserId string`, not bare `string`.
- **No `interface{}`/`any` without justification:** Go 1.18+ generics reduce the need.
- **`any` requires a type assertion or switch:** never use the value without narrowing.
```go
type UserId string
type OrderId string
// UserId and OrderId are distinct; cannot be mixed
func GetUser(id UserId) (*User, error) { ... }
```
## Error Handling (Errors P1 Errors are Data)
- **Errors are values:** `error` is an interface, not an exception. Handle explicitly.
- **Sentinel errors with `errors.Is`:**
```go
var ErrNotFound = errors.New("not found")
if errors.Is(err, ErrNotFound) { ... }
```
- **Wrap with context:** `fmt.Errorf("get user %d: %w", id, err)`.
- **Never `_ = err`:** swallowed error (Errors P2). Handle or return.
- **Custom error types with `errors.As`:**
```go
type ValidationError struct {
Field string
Msg string
}
func (e *ValidationError) Error() string { return e.Field + ": " + e.Msg }
```
## Concurrency (Concurrency — Go's strength)
- **Goroutines + channels** for message passing (P5 Lock Minimization).
- **`context.Context` for cancellation and timeout:** every function that does I/O takes a `ctx`.
- **`sync.Mutex` scoped minimally:** not held across I/O (P3 Lock Scope).
- **Bounded channels:** `make(chan T, N)`, not unbounded (P9 Bounded Queues).
```go
func fetchWithTimeout(ctx context.Context, url string) (*Response, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
return doFetch(ctx, url)
}
```
## Immutability (Concurrency P1)
- **Pass by value for small structs; pass by pointer for large or mutable.**
- **No mutation of method receivers:** use a value receiver, not a pointer receiver, for read-only methods.
- **Copy-on-write for shared state:** return a new struct, not a mutated one.
## Nullability (C1)
- **Pointers can be nil; values cannot.** Be explicit: `*User` (nullable) vs `User` (not).
- **`nil` check before deref:** a nil deref is a panic.
- **Return `(T, error)`, not `(*T, nil)`:** avoid the "nil pointer" trap.
## Testing (Testing)
- **`testing` package + `testify/assert`** or stdlib only.
- **Table-driven tests:** `[]struct{ name string; input X; want Y }`.
- **`t.Parallel()`** for independent tests (P2 Independence).
- **`httptest` for HTTP handlers; `sqlite` or testcontainers for DB.**
## Observability (Observability P1)
- **`slog` (stdlib, Go 1.21+) or `zap`/`zerolog`:** structured logs.
- **`context.Context` carries `trace_id`:** propagated via middleware.
- **No `fmt.Println`:** use the logger.
## Tooling (DevOps P2)
- **`go vet` + `golangci-lint`:** lint.
- **`gofmt`/`goimports`:** format (automated, not debated).
- **`go test -race` in CI:** race detector (Concurrency P6 No Silent Races).
- **`go mod tidy` + committed `go.sum`:** reproducible builds.