Coding Patterns
Purpose
Provide portable defaults for writing code that is explicit, intention-revealing, easy to test, and easy to maintain across languages.
When to use this skill
- Choosing general coding defaults for a new feature or repository.
- Refactoring code that is hard to read, weakly typed, or over-coupled.
- Deciding when comments help and when they are noise.
- Designing a CLI or automation surface.
- Reviewing whether tests actually cover risky behavior.
Scope Boundaries
- Use this skill for language-agnostic defaults such as naming, comments, branching, CLI ergonomics, and testing posture.
- Use
ref-sp-dev-projects-architecturefor folder layout, feature boundaries, and shared-utility decisions. - Use
ref-sp-py-python,ref-sp-js-javascript, orref-sp-js-typescriptfor syntax- and runtime-specific guidance. - Use a repo-local conventions skill (in this repo,
ref-sp-dev-repo-conventions) when the question is about a specific repository's exact paths or commands.
Defaults
- Prefer strict typing when the language supports it.
- Prefer explicit boundaries over clever inference at I/O edges.
- Prefer names that scream intent over vague verbs.
- Prefer early returns over deep nesting.
- Prefer small focused functions over multi-purpose handlers.
- Prefer modules whose import has no side effects; defer real work to functions, factories, or explicit initialization.
- Prefer safe CLI defaults and discoverable help.
- Prefer focused tests over broad integration-style guesswork.
Task Framing
| Command or action | What | Why | When | Expected outcome |
|---|---|---|---|---|
| Pick naming and data-boundary defaults | Choose intention-revealing names and explicit validation or narrowing points. | Weak names and fuzzy I/O boundaries make every later refactor harder. | When starting a new feature or cleaning up unclear code. | Call sites, helpers, and data shapes read clearly without private context. |
| Shape a CLI surface | Choose subcommands, flags, help text, and safe defaults deliberately. | CLI ergonomics become sticky quickly once other people start using them. | When creating or revising a command-line workflow. | The command is discoverable, predictable, and safe to run. |
| Review comments and tests | Decide which constraints deserve comments and which branches deserve tests. | Documentation and tests are expensive if they are broad but shallow. | When finishing a risky change or reviewing a refactor. | Comments explain real constraints and tests cover the most fragile behavior. |
Core Rules
Typing and data boundaries
- Type public APIs, exported helpers, and shared data structures clearly.
- Treat external input as untrusted until it is narrowed or validated.
- Prefer type guards, validation helpers, discriminated unions, or tagged states over unchecked casts.
- Avoid
any, untyped containers, and stringly-typed state when the language gives you better options.
Naming and structure
- Use names that describe the business meaning or effect of the code.
- Prefer names like
parseInvoiceCsv,loadUserProfile, orrenderDashboard. - Avoid names like
handleData,doThing,misc, orhelperswhen a narrower name exists. - Split code by responsibility before it becomes hard to name mentally.
Control flow
- Use early exits to remove nesting and make the happy path obvious.
- Keep conditions local and explicit rather than encoding them through side effects.
- If a branch exists because of a business rule, name that rule in code or in a short comment.
Module initialization and import side effects
- Treat importing a module as binding names only: it must not open connections, read files or environment, call the network, run expensive work, or instantiate stateful clients, pools, or singletons.
- Keep modules order-independent. If changing import order changes behavior, something is doing work at import time that should be deferred.
- Prefer a factory function, a lazy accessor, or caller-injected dependencies over a ready-made instance built at module scope.
- Pure constants and frozen lookup data at module scope are fine; the rule targets work and side effects, not values.
- Distinguish an importable module from an application entry point or composition root. Wiring things up at an entry point — an app root, a
main(), a provider setup — is expected, and some frameworks recommend it. The rule is that importing a module must not trigger the work, not that construction can never happen at module scope. - Allow a module-scope exception only as a deliberate, documented decision with a stated reason, never as something that happens by accident.
- Give tests more latitude here because their modules are small and short-lived, but still avoid hidden import-order coupling.
Comments
- Comment why, constraints, invariants, or business context.
- Do not comment what the code already says clearly.
- Add comments when a rule is externally imposed, legally required, surprising, or easy to break during refactors.
- Treat a comment's assertion as a claim, not decoration: verify a stated invariant or safety condition (such as "safe because X") against the code before writing it as fact.
CLI ergonomics
- Prefer verb-oriented subcommands for multi-action CLIs.
- Provide long flags and short aliases for the flags used most often.
- Use predictable pairs like
--fromand--tofor source and destination. - Default to the current working directory when that behavior is unsurprising.
- Add
--dry-runfor destructive or high-impact actions. - Make
--helpconcrete, with real examples and safe defaults.
Testing
- Add focused tests for non-trivial logic, error handling, and boundary conditions.
- Cover the branch that is easiest to break, not just the happy path.
- Keep tests readable enough that they explain the intended behavior.
- Prefer a few well-named fixtures/builders over huge shared setup blocks.
Validation
- Public functions and shared structures are typed clearly.
- Names reveal intent without needing surrounding explanation.
- Comments explain non-obvious constraints rather than narrating syntax.
- Importing a module does no I/O or heavy construction; such work is deferred to factories, lazy accessors, or an explicit entry point.
- CLI flags are consistent, discoverable, and safe.
- Tests cover risky logic and failure modes, not only success paths.
References
- Read
./references/checklist.mdfor a quick review pass when applying or revising these defaults. - Read
./assets/trigger-eval-queries.example.jsonwhen testing whether the description triggers on the right requests.