- Use
anyinstead ofinterface{}(Go 1.18+) - Correct:
map[string]any - Avoid:
map[string]interface{}
- Place a summary comment above the function declaration
- Do not use sequential step comments (
// step 1,// step 2, etc) - The function comment should concisely explain what the function does, not how
- Include inputs, outputs, and notable behavior (e.g., side effects, locking)
Example:
// LoadState reads .alpf/state.json with a shared lock to prevent concurrent writes.
// Returns an error if the file cannot be read or parsed.
func LoadState(projectPath string) (*pkg.ExecutionState, error) {
statePath := filepath.Join(projectPath, ".alpf", "state.json")
f, err := os.Open(statePath)
if err != nil {
return nil, fmt.Errorf("failed to open state file: %w", err)
}
defer f.Close()
// Implementation details...
}- Use
min()andmax()builtins (Go 1.21+) instead of if/else for simple comparisons - Correct:
delay = min(calculated, maxDelay) - Avoid:
if calculated > maxDelay { delay = maxDelay } else { delay = calculated }
- Always wrap errors with context using
fmt.Errorf("context: %w", err) - Return errors early, don't nest deeply
- Use meaningful error messages that indicate which operation failed
- Group imports: stdlib, then external packages, separated by blank lines
- Use
goimportsor manually organize if needed
- Use descriptive names; avoid single-letter vars except in loops (
i,j,k) - Acronyms:
IDnotId,JSONnotJson,HTTPnotHttp - Prefer
projectPathoverporpath
- Go 1.25.4 or later
- Cobra CLI framework (included via
go.mod)
go build -o alpf ./cmd/alpf./alpf [flags] [args]go install ./cmd/alpfgo test ./...go test ./internal/store
go test ./internal/executorgo test -v ./...go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.outgo test -run TestFunctionName ./internal/storefind . -name "*.go" | entr go test ./...- Config: Static configuration (loaded once at startup)
- ExecutionState: Dynamic runtime state (persisted to
.alpf/state.json) - AttemptRecord: Individual attempt history (appended to
.alpf/history.jsonl)
- Shared lock: When reading state (multiple readers allowed)
- Exclusive lock: When writing state (single writer)
- Always
deferunlock immediately after acquiring lock
- Return errors from functions
- Wrap with context using
%wformat - Only log/handle errors at the boundary (CLI level)
- Use
map[string]anyfor flexible validator/executor configs - Type assert values when accessing:
config["key"].(string)
- Write concise doc comment above function
- Use consistent parameter order: context-like params first, then data params
- Return values last, error last
- Simplify control flow (use
min/max, avoid unnecessary nesting)
- Place in same package as code being tested
- Name file
*_test.go - Use
TestFunctionNameconvention - Test both happy path and error cases
- Include the operation that failed: "failed to open config file: %w"
- Use lowercase unless it's a proper noun
go fmt ./...golangci-lint run ./...interface{}→ useany- If/else for min/max → use builtin
min()/max() - Unused variables → remove or use
_