4e433158cd
---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---
3.4 KiB
3.4 KiB
Go — Language Application
How Atelier's domain principles apply in Go specifically. Derives from
domains/docs.
Derived Docs
- go-types.md — named types, generics, interfaces, type assertion discipline.
- go-tooling.md — go vet, golangci-lint, go test -race, module discipline.
- go-concurrency.md — goroutines, channels, context, select, sync primitives.
- 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 barestring. - No
interface{}/anywithout justification: Go 1.18+ generics reduce the need. anyrequires a type assertion or switch: never use the value without narrowing.
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:
erroris an interface, not an exception. Handle explicitly. - Sentinel errors with
errors.Is:
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:
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.Contextfor cancellation and timeout: every function that does I/O takes actx.sync.Mutexscoped minimally: not held across I/O (P3 Lock Scope).- Bounded channels:
make(chan T, N), not unbounded (P9 Bounded Queues).
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) vsUser(not). nilcheck before deref: a nil deref is a panic.- Return
(T, error), not(*T, nil): avoid the "nil pointer" trap.
Testing (Testing)
testingpackage +testify/assertor stdlib only.- Table-driven tests:
[]struct{ name string; input X; want Y }. t.Parallel()for independent tests (P2 Independence).httptestfor HTTP handlers;sqliteor testcontainers for DB.
Observability (Observability P1)
slog(stdlib, Go 1.21+) orzap/zerolog: structured logs.context.Contextcarriestrace_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 -racein CI: race detector (Concurrency P6 No Silent Races).go mod tidy+ committedgo.sum: reproducible builds.