2.2 KiB
2.2 KiB
Go Self-Review Checklist
Load this file after completing the universal self-review in
SKILL.md, when the code under review is Go.
Resource Cleanup
- No bare
defer X.Close()— all deferred closers use error-checked closures withslog - No
//nolint:errcheckdirectives anywhere in new code - Transaction rollbacks check for
sql.ErrTxDonebefore logging - HTTP response bodies are drained (
io.Copy(io.Discard, ...)) before closing
Correct Patterns
// ✅ Row/statement/connection Close
defer func() {
if err := rows.Close(); err != nil {
slog.Warn("failed to close rows", "error", err, "operation", "<operation>")
}
}()
// ✅ Transaction Rollback
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
slog.Error("failed to rollback transaction", "error", err, "operation", "<operation>")
}
}()
// ✅ HTTP Response Body
defer func() {
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
slog.Warn("failed to drain response body", "error", err)
}
if err := resp.Body.Close(); err != nil {
slog.Warn("failed to close response body", "error", err)
}
}()
Logging
- No
fmt.Printf/fmt.Println/log.Printf— onlyslogin production code - All log calls use structured key-value pairs (no
fmt.Sprintfinside log messages) - Error logs include
"error", erras a key-value pair
Error Handling
- All errors are wrapped with context using
%w:fmt.Errorf("doing X: %w", err) - No duplicate wrapping of the same error
- Sentinel errors used for expected conditions (
ErrNotFound,ErrUnauthorized)
Static Analysis
go vet ./...passes with zero issues- No new
//nolint:directives without a// NOLINT:rationale comment //nolint:errcheckspecifically is never used — handle the error instead
References
- Go Idioms and Patterns @go-idioms-and-patterns.md (§ Idiomatic Patterns, § Formatting and Static Analysis)
- Logging and Observability Principles @logging-and-observability-principles.md (§ Go/slog)
- Error Handling Principles @error-handling-principles.md (§ Resource Cleanup)