496303471d
---ci--- project: atelier phase: 7 milestone: v0.1 status: complete phase_role: final milestone_complete: true requirements: covered: [ATELIER-01, ATELIER-02, ATELIER-03, ATELIER-04, ATELIER-05, ATELIER-06, ATELIER-07, ATELIER-08, ATELIER-09, ATELIER-10, ATELIER-11, ATELIER-12, ATELIER-13, ATELIER-14, ATELIER-15, ATELIER-16, ATELIER-17, ATELIER-18, ATELIER-19, ATELIER-20, ATELIER-21, ATELIER-22, ATELIER-23, ATELIER-24, ATELIER-25, ATELIER-26, ATELIER-27, ATELIER-28, ATELIER-29, ATELIER-30, ATELIER-31, ATELIER-32, ATELIER-33, ATELIER-34, ATELIER-35] partial: [] ship: milestone: v0.1 type: NFR tag: v0.0.7 merge: milestone/v0.1-atelier -> main release: https://git.cloudinit.dev/cloudinit-bot/atelier/releases/tag/v0.0.7 ---/ci--- Milestone v0.1 — Initial Framework (NFR, complete). 8 core principles (C1-C8), 11 domains, 110 domain principles, 27 derived docs, 4 good + 3 bad examples, 4 language docs, full matrix, 3 review docs. All 35 requirements covered. 7 patches (v0.0.0 pre-execution through v0.0.7 final). v0.0.7 IS the v0.1.0 milestone release.
82 lines
3.0 KiB
Markdown
82 lines
3.0 KiB
Markdown
# Go — Language Application
|
|
|
|
> How Atelier's domain principles apply in Go specifically. Derives from `domains/` docs.
|
|
|
|
## 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. |