---
inclusion: always
---

# Clean Code & Best Practices

These rules apply to ALL code you write in this workspace. Follow them by
default unless the user explicitly asks otherwise. The goal: code a senior
engineer would happily approve in review.

---

## 1. Naming

- Use **descriptive, intention-revealing names**. A name explains *why* it
  exists and *what* it does without needing a comment.
- Avoid abbreviations and single letters (`d`, `tmp`, `data`, `info`, `obj`),
  except for well-known loop counters (`i`, `j`) or math/domain conventions.
- Functions are **verbs** (`calculateTotal`, `fetch_user`); variables and
  classes are **nouns** (`userCount`, `InvoiceService`); booleans read as a
  yes/no question (`isActive`, `has_permission`, `can_edit`).
- Pick **one term per concept** (`get` vs `fetch` vs `retrieve`) and stay
  consistent across the codebase.
- Follow the language's idiomatic convention:
  - **JS/TS:** `camelCase` vars/functions, `PascalCase` classes/types,
    `UPPER_SNAKE_CASE` constants.
  - **Python:** `snake_case` vars/functions, `PascalCase` classes,
    `UPPER_SNAKE_CASE` constants.
  - **Go:** `camelCase` private, `PascalCase` exported.
  - **SQL:** `snake_case` columns/tables (`created_at`, `user_profiles`).
  - Match surrounding code if conventions already exist.

## 2. Functions

- **Single Responsibility:** a function does one thing and does it well.
- Keep functions **short** — extract helpers as soon as one function does
  more than one thing. A hard line count is less useful than this question:
  *"can I summarize this function in one sentence?"*
- Limit parameters. **For more than 2-3 params, use an options object** so
  callers stay readable and order doesn't matter:

  ```ts
  // Avoid
  createUser(name, email, age, role, isAdmin, sendEmail);

  // Prefer
  createUser({ name, email, age, role, isAdmin, sendEmail });
  ```

  ```python
  # Python: prefer keyword-only args via *
  def create_user(*, name: str, email: str, age: int, role: str = "user") -> User: ...
  ```

- **No hidden side effects.** A function called `getUser` must not mutate
  global state.
- Prefer **early returns / guard clauses** over deep nesting:

  ```ts
  function process(user: User | null) {
    if (!user) return;
    if (!user.isActive) return;
    // ...
  }
  ```

## 3. Avoid Duplication (DRY)

- Don't copy-paste logic. Extract shared behavior into functions, modules, or
  utilities.
- But **don't over-abstract** — a little duplication beats the wrong
  abstraction. Wait until a pattern appears **2–3 times** before generalizing.
  Premature abstractions are very expensive to undo.

## 4. Constants Over Magic Values

No magic numbers or unexplained string literals inside logic.

```ts
const OrderStatus = { Shipped: 3 } as const;
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
if (status === OrderStatus.Shipped) { /* ... */ }
setTimeout(refresh, ONE_DAY_MS);
```

```python
ONE_DAY_SECONDS = 24 * 60 * 60
class OrderStatus(IntEnum): SHIPPED = 3
```

## 5. Error Handling

- **Never swallow errors silently** — no empty `catch {}` / bare `except:`.
- **Fail fast:** validate inputs at the boundary, throw/return early on
  invalid state.
- Throw **meaningful, specific errors with context** — not
  `throw new Error("error")`.
- Handle errors at the level that can actually do something about them; don't
  catch-and-rethrow without adding value.
- **Clean up resources** in `finally` or with language-appropriate constructs:

  ```python
  with open(path) as f:           # Python
      ...
  ```

  ```go
  f, err := os.Open(path); if err != nil { return err }
  defer f.Close()                 // Go
  ```

  ```ts
  // TS / Node 22+
  await using db = openConnection();
  ```

## 6. Comments & Documentation

- **Self-documenting code first** — reach for comments only when the *why*
  isn't obvious.
- Explain **why**, not **what**. The code already shows the what.
- **Delete commented-out code.** Version control remembers it.
- Add doc comments (JSDoc / docstrings / Go doc) for public APIs and anything
  with non-obvious behavior.
- Keep comments **truthful** — update them when the code changes.

## 7. Types & Data

- Prefer **strong typing.** In TS, avoid `any`; use `unknown` + narrowing when
  the type is genuinely unknown. In Python, use type hints + `mypy`/`pyright`.
- **Make illegal states unrepresentable** — use enums, discriminated unions,
  precise types instead of loose strings/flags.
- Prefer **immutability:** `const`, `readonly`, frozen objects, pure
  transformations, Python `dataclass(frozen=True)`, Go value types.
- **Validate external/untrusted data at the boundary** with a schema
  (Zod / Pydantic / `encoding/json` + checks). Don't trust the network.

## 8. Structure & Organization

- One clear responsibility per file/module. Group related code together.
- Keep the **public surface small** — export only what's needed.
- Order top-down: high-level/public functions first, low-level helpers below.
- **Separate concerns:** business logic, I/O, and presentation don't mix in
  the same file.

## 9. Formatting & Style

- Match the project's existing formatter/linter (Prettier, ESLint, Black,
  Ruff, gofmt, sqlfluff). Never fight the formatter.
- Consistent indentation, spacing, and import ordering.
- Keep lines short and readable.
- Remove unused imports, variables, and dead code on every touch.

## 10. Testing

- Write **testable code:** pure functions, dependency injection, no hidden
  global state.
- When the user asks for tests, cover the **happy path, edge cases, and
  error cases** with clear, behavior-describing test names
  (`it("rejects expired tokens")`, not `it("test1")`).
- **Do NOT add tests automatically** unless requested — but always keep code
  test-friendly.

## 11. Security & Safety

- **Never hardcode secrets** — use environment variables / a secret manager.
- **Sanitize and validate all user input.** Use parameterized queries — never
  string-concatenate SQL:

  ```sql
  -- ❌ vulnerable
  query = "SELECT * FROM users WHERE id = " + req.id

  -- ✅ parameterized
  SELECT * FROM users WHERE id = $1;
  ```

- Apply the **principle of least privilege** (DB users, API tokens, IAM).
- **Never log** passwords, tokens, full PII, or auth headers.

## 12. Performance (with judgment)

- Write clear code first; optimize only when there's a real, measured need.
- Avoid obvious inefficiencies: N+1 queries, unnecessary loops over large
  data, repeated expensive calls, fetching whole rows when one column is
  needed.
- Don't sacrifice readability for micro-optimizations without justification.
- Cache only what you can invalidate correctly.

---

## 13. Concurrency & Async

- **Don't `await` sequentially when calls are independent.** Parallelize with
  `Promise.all` / `asyncio.gather` / `errgroup`:

  ```ts
  // Sequential (slow)
  const user = await fetchUser(id);
  const orders = await fetchOrders(id);

  // Parallel
  const [user, orders] = await Promise.all([fetchUser(id), fetchOrders(id)]);
  ```

  ```python
  user, orders = await asyncio.gather(fetch_user(id), fetch_orders(id))
  ```

- **Don't fan out unbounded.** Cap concurrency with `pLimit`, a semaphore, or
  a worker pool. 10k parallel HTTP calls will take down something.
- Make every **external action idempotent** (use an idempotency key) — the
  network will retry without telling you.
- **Cancellation:** pass `AbortSignal` / `context.Context` / cancellation
  token through every async layer. Don't strand requests after the user
  navigates away.
- Beware **race conditions:** when two writes hit the same row, the last
  write wins silently. Use DB-level locks, optimistic concurrency
  (`updatedAt` check), or queue serialization.
- `try/catch` around `await`, not around the call that returns the promise:

  ```ts
  try { await save(); } catch (e) { /* handle */ }
  ```

## 14. Logging

- **Use levels deliberately:**
  - `debug` — fine-grained dev info, off in prod
  - `info` — normal app events (request handled, job finished)
  - `warn` — recoverable problem, worth a human glance
  - `error` — a failed operation that needs investigation
  - `fatal` — process is going down

- Prefer **structured logging** over string interpolation — searchable,
  queryable, machine-parsable:

  ```ts
  // ❌ loses fields
  log.info(`Order ${id} for ${userId} took ${ms}ms`);

  // ✅ keyed
  log.info({ orderId: id, userId, durationMs: ms }, "order processed");
  ```

- **Never log:** passwords, tokens, auth headers, full credit-card numbers,
  raw PII (emails OK if redacted where required).
- Log at **boundaries** (request in, request out, external call) — not on
  every line. Noisy logs hide real signal.
- Include a **correlation id / request id** so a single user action can be
  traced across services.
- High-volume paths: **sample** (`log 1 in 100`) instead of dropping detail.

## 15. Dependencies & Version Control

**Dependencies**

- Adding a new dependency is a cost: security surface, build time, maintenance.
  Ask: *"can I do this in 30 lines of clear code?"* If yes, write the 30 lines.
- Prefer mature, actively maintained packages. Check the date of the last
  release and open issues count.
- **Pin versions** in lockfiles (`package-lock.json`, `poetry.lock`,
  `go.sum`). Don't run `npm install` in CI without `--frozen-lockfile`
  equivalents.
- Audit periodically (`npm audit`, `pip-audit`, `govulncheck`).

**Git commit hygiene**

- One logical change per commit. *"Fix login bug AND refactor router AND
  bump deps"* is three commits, not one.
- Commit message: a short imperative subject (`Fix off-by-one in pagination`),
  then a blank line, then a paragraph on **why** (context, trade-offs, link
  to issue).
- Don't commit:
  - `.env`, credentials, `.DS_Store`, build artifacts, `node_modules`
  - Commented-out code "for later"
  - Half-finished work on `main` (use a branch)
- Never `git push --force` to a shared branch without explicit agreement.

**Pull requests / code review**

- Keep PRs small (**< 400 lines diff** when possible). Big PRs get rubber-
  stamped because nobody can hold them in their head.
- The PR description tells the reviewer: *what changed, why, how to verify*.
  Don't make them read the diff to figure out the why.
- As reviewer: respond within a day. Stale PRs rot. Prefer "request changes"
  with concrete suggestions over vague "looks risky".

---

## Workflow Expectations

1. **Understand before coding** — clarify ambiguous requirements instead of
   guessing.
2. **Work incrementally** — structure first, then core logic, then edge cases.
3. **Read before editing** — never modify code you haven't looked at.
4. **Leave it cleaner** — Boy Scout Rule: improve nearby code you touch,
   within the scope of the task.
5. **Explain key decisions** — briefly note non-obvious trade-offs.

## The Litmus Test

Before finishing, ask: *"Would a senior engineer approve this in code
review?"* If a function is too long, a name is unclear, an error is
unhandled, logic is duplicated, an async call is sequential when it could
be parallel, a secret is hardcoded, or a log line leaks PII — fix it before
presenting the result.
