|
| 1 | +--- |
| 2 | +name: way-go-style |
| 3 | +description: Guide for writing idiomatic, effective, and standard Go code. Use this skill when writing, refactoring, or reviewing Go code to ensure adherence to established conventions and best practices. |
| 4 | +--- |
| 5 | + |
| 6 | +# Way Go Style |
| 7 | + |
| 8 | +## Project Setup (AGENTS.md) |
| 9 | + |
| 10 | +Go projects MUST include this skill's **Way Specific Conventions** in their `AGENTS.md` file to ensure compliance. |
| 11 | + |
| 12 | +1. **Reference this skill**: Under "Local Skills". |
| 13 | +2. **Copy Conventions**: Copy the **Way Specific Conventions** section below into `AGENTS.md` under "Key Conventions". |
| 14 | + |
| 15 | +## Way Specific Conventions |
| 16 | + |
| 17 | +- **Testing**: Use standard `testing` and `github.com/google/go-cmp/cmp` **only**. No frameworks (Testify, Ginkgo, etc.). |
| 18 | +- **Linting**: Run `GolangCI-Lint` v2. Configure via project-specific `.golangci.yml`. |
| 19 | +- **Build**: Use `way-magefile` skill. |
| 20 | +- **Encore**: Use `encore-go-*` skills. Encore conventions (e.g., globals) take precedence. |
| 21 | + |
| 22 | +## Overview |
| 23 | + |
| 24 | +This skill provides a condensed reference for writing high-quality Go code, synthesizing advice from "Effective Go", Google's "Code Review Comments", and other authoritative sources. It focuses on idiomatic usage, correctness, and maintainability. |
| 25 | + |
| 26 | +## Effective Go Idioms |
| 27 | + |
| 28 | +Critical idioms from [Effective Go](references/effective_go.html). |
| 29 | + |
| 30 | +### Control Flow & Error Handling |
| 31 | +- **Defer Evaluation:** Arguments to deferred functions are evaluated **immediately** at the call site (not at execution). |
| 32 | +- **Init Scope:** Use `if err := f(); err != nil` to restrict variable scope. |
| 33 | +- **Switch:** Use tagless `switch { case condition: ... }` instead of long `if-else` chains. |
| 34 | +- **Internal Panic/Recover:** Use `panic` to simplify deep error handling in complex internal code (e.g., parsers), but **always** `recover` at the package boundary to return a standard `error`. |
| 35 | + |
| 36 | +### Types & Interfaces |
| 37 | +- **Functional Adapters:** Define methods on function types (e.g., `type MyFunc func()`) to satisfy interfaces. See `http.HandlerFunc`. |
| 38 | +- **Interface Verification:** Use a global blank assignment to ensure a type satisfies an interface at compile time: `var _ Interface = (*Type)(nil)`. |
| 39 | + |
| 40 | +## Google Style Decisions & Best Practices |
| 41 | + |
| 42 | +Key decisions from the [Google Go Style Guide](references/google/index.md) and [Code Review Comments](references/CodeReviewComments.md). |
| 43 | + |
| 44 | +### Core Principles |
| 45 | +- **Clarity:** "Clear to the reader" is priority #1. Explain *why*, not just *what*. |
| 46 | +- **Simplicity:** "Least Mechanism". Prefer core constructs (slices, maps) over complex abstractions. |
| 47 | +- **Concision:** High signal-to-noise ratio. Avoid boilerplate. |
| 48 | + |
| 49 | +### Naming & Structure |
| 50 | +- **Packages:** Single-word, lowercase (e.g., `task`, not `task_manager`). **Avoid** `util`, `common`. |
| 51 | +- **Receivers:** 1-2 letter abbreviations (e.g., `c` for `Client`). **NEVER** use `me`, `this`, `self`. |
| 52 | +- **Constants:** Always `MixedCaps` (e.g., `MaxLength`), even if exported. **NEVER** `MAX_LENGTH`. |
| 53 | +- **Getters:** `Owner()` (not `GetOwner`). |
| 54 | +- **Interfaces:** One-method interfaces -> `Method` + `-er` (e.g., `Reader`). Define in the **consumer** package. Keep them small. |
| 55 | + |
| 56 | +### Functions & Methods |
| 57 | +- **Receiver Type:** |
| 58 | + - **Pointer (`*T`):** If mutating, contains `sync.Mutex`, or large struct. |
| 59 | + - **Value (`T`):** Maps, channels, functions, small immutable structs. |
| 60 | + - **Consistency:** Prefer all pointers or all values for a type's methods. |
| 61 | +- **Pass Values:** Don't pass pointers to small types (`*string`, `*int`) just to save memory. |
| 62 | +- **Synchronous:** Prefer synchronous APIs. Let the caller decide to use goroutines. |
| 63 | +- **Must Functions:** `MustXYZ` panic on failure. Use **only** for package-level init or test helpers. |
| 64 | + |
| 65 | +### Error Handling |
| 66 | +- **Flow:** Handle errors immediately (`if err != nil { return err }`). Keep "happy path" unindented. Avoid `else`. |
| 67 | +- **Structure:** Use `%w` with `fmt.Errorf` to wrap errors for programmatic inspection (`errors.Is`). |
| 68 | +- **Panics:** **Never** panic in libraries. Return errors. `log.Fatal` is okay in `main`. |
| 69 | +- **Strings:** Lowercase, no punctuation (e.g., `fmt.Errorf("something bad")`) for easy embedding. |
| 70 | + |
| 71 | +### Concurrency |
| 72 | +- **Lifetimes:** Never start a goroutine without knowing how it stops. |
| 73 | +- **Context:** Always first arg `ctx context.Context`. **Never** store in structs. |
| 74 | +- **Copying:** **Do not copy** structs with `sync.Mutex` or `bytes.Buffer`. |
| 75 | + |
| 76 | +### Testing |
| 77 | +- **Framework:** Use `testing` package. No assertion libraries (use `cmp` for diffs). |
| 78 | +- **Helpers:** Mark setup/teardown functions with `t.Helper()`. |
| 79 | +- **Failure Messages:** `YourFunc(%v) = %v, want %v`. (Got before Want). |
| 80 | +- **Table-Driven:** Use field names in struct literals for clarity. |
| 81 | +- **Subtests:** Use `t.Run()` for clear scope and filtering. Avoid slashes in names. |
| 82 | + |
| 83 | +### Global State & Init |
| 84 | +- **Avoid Globals:** Libraries should not rely on package-level vars. Allow clients to instantiate (`New()`). |
| 85 | +- **Initialization:** Use `:=` for non-zero values. Use `var t []T` (nil) for empty slices. |
| 86 | +- **Imports:** Group order: Stdlib, Project/Vendor, Side-effects (`_`). No `.` imports. |
| 87 | + |
| 88 | +## Practical Go Cheat Sheet |
| 89 | + |
| 90 | +Best practices for maintainable Go from **Dave Cheney's** [Practical Go](references/dave-cheney-practical-go.md). |
| 91 | + |
| 92 | +### Guiding Principles |
| 93 | +- **Simplicity, Readability, Productivity:** The core values. Clarity > Brevity. |
| 94 | +- **Identifiers:** Choose for clarity. Length proportional to scope/lifespan. Don't include type in name (e.g., `usersMap` -> `users`). |
| 95 | + |
| 96 | +### Design & Structure |
| 97 | +- **Package Names:** Name for what it *provides* (e.g., `http`), not what it contains. Avoid `util`, `common`. |
| 98 | +- **Project Structure:** Prefer fewer, larger packages. Arrange files by import dependency. |
| 99 | +- **API Design:** Hard to misuse. Avoid multiple params of same type. Avoid `nil` params. |
| 100 | +- **Interfaces:** Let functions define behavior they require (e.g., take `io.Writer` not `*os.File`). |
| 101 | +- **Zero Value:** Make structs useful without explicit initialization (e.g., `sync.Mutex`, `bytes.Buffer`). |
| 102 | + |
| 103 | +### Concurrency & Errors |
| 104 | +- **Concurrency:** Leave it to the caller. Never start a goroutine without knowing when/how it stops. |
| 105 | +- **Errors:** Eliminate error handling by eliminating errors (e.g., `bufio.Scanner`). Handle errors once (don't log AND return). |
| 106 | +- **Return Early:** Use guard clauses. Keep the "happy path" left-aligned. |
| 107 | + |
| 108 | +## Available References |
| 109 | + |
| 110 | +Detailed documentation available in the `references/` directory: |
| 111 | + |
| 112 | +- **[Effective Go](references/effective_go.html):** (HTML) The foundational guide to idiomatic Go. |
| 113 | +- **[Code Review Comments](references/CodeReviewComments.md):** Common comments made during Go code reviews at Google. |
| 114 | +- **[Google Style Guide](references/google/index.md):** Complete set of Google's Go style documents. |
| 115 | + - [Guide](references/google/guide.md): Core guidelines. |
| 116 | + - [Decisions](references/google/decisions.md): Normative style decisions. |
| 117 | + - [Best Practices](references/google/best-practices.md): Evolving guidance. |
| 118 | +- **[Practical Go](references/dave-cheney-practical-go.md):** **Dave Cheney's** advice on writing maintainable Go programs. |
0 commit comments