Skip to main content

coding-style

The user's personal coding style. Load before writing, refactoring, or reviewing code in any language or project — covers magic numbers/strings, separation of I/O from domain logic, guard clauses, exhaustive mappers instead of switch, no nested ternaries, function shape, types in a separate directory, and verification before finishing.

Source facts

Repository
bioleyl/swcode
Last source activity
November 3, 2026 at 08:46
Detected SKILL.md language
English
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
coding-style
description
The user's personal coding style. Load before writing, refactoring, or reviewing code in any language or project — covers magic numbers/strings, separation of I/O from domain logic, guard clauses, exhaustive mappers instead of switch, no nested ternaries, function shape, types in a separate directory, and verification before finishing.
# Coding style Understand the existing architecture and conventions before changing code. Make the smallest change that solves the problem and preserve unrelated behavior. ## No magic numbers Always use named `const` values for literal numbers that carry domain meaning. A bare `100` or `60` tells the reader nothing; `SCORE.nameExactMatch` or `MAX_RETRY_COUNT` communicates intent and makes future adjustments localized. ## No magic strings Always use named `const` values for literal strings that carry domain meaning. A bare `"project"` or `"user"` tells the reader nothing; `SCOPE.project` or `LOCKFILE_PATH` communicates intent. This applies to status codes, environment variable names, file paths, and any string used in more than one place. ## Structure - Keep responsibilities separated: domain rules should not perform I/O, and orchestration should not contain low-level implementation details. - Prefer small functions with one clear responsibility and descriptive names. - Keep pure logic deterministic and move filesystem, network, time, environment, and process effects to explicit boundaries. - Prefer simple composition over premature abstractions. Introduce an abstraction when it removes a real dependency or clarifies a stable boundary. ## Control flow - Use guard clauses and early returns for invalid input, errors, and exceptional cases. - Use `if` only as a guard clause that returns (or throws) early. For any other branching, use a simple ternary, an exhaustive mapper, or a named predicate or function. - Prefer exhaustive mappers over `switch` statements for type- or case-based logic. Use a typed map such as `const labels: Record<MyType, string> = { ... }`; adding a member to `MyType` then produces a compile-time error until the mapper is updated. - Never use nested ternaries. If the logic needs more branching than a simple ternary or an early return, the function is doing too much: split it into smaller functions with clear responsibilities. - Avoid deeply nested loops and callbacks; extract the inner operation when it needs its own explanation. ## Function shape - Prefer `const` over `let`. If a value would need to be assigned across a `try` block or multiple branches, extract that work into a named function that returns a `Result` or an explicit value. - Keep orchestration functions short and phase-oriented. Extract setup, validation, execution, rollback, cleanup, and rendering into separate helpers when they have distinct responsibilities. - Keep effectful boundaries explicit. A filesystem or network helper should perform one operation and return a structured result; callers should coordinate those results rather than mixing low-level effects with business rules. - Avoid mutable state used only to carry context between branches, such as a `currentPath` variable for error reporting. Pass the context into a helper or return it with the operation result. - Prefer named predicates and helpers over inline conditionals when they make a failure path or invariant easier to understand. ## Type safety (TypeScript) - Never use `any`. Use `unknown` only at system boundaries (parsed JSON, network, environment, `catch`), and narrow it with a type guard or validator before use. - Never cast external data with `as Foo`. Narrow or validate it instead. `as const` and `satisfies` are fine, since they narrow literals without overriding the checker. - Model mutually exclusive states as a discriminated union, not as optional fields that can contradict each other. This also feeds the exhaustive mappers above. - Use `interface` for object shapes and `type` for unions and intersections. - Use `undefined` for absent values, not `null`, unless an external contract requires `null`. ## Types directory (TypeScript) - Code files hold only code. Declare every `interface` and `type` in a `types/` directory at the root of its source tree (`src/types/`, `frontend/src/types/`, `tests/types/`). - A file left with only types moves whole into `types/`, and the empty code file is deleted (ports, definitions). - Name every file in `types/` with the `.types.ts` suffix (`session.types.ts`), and import it with that suffix. - Keep Zod schemas in the code file, and the types derived from them (`z.infer`, `z.input`) beside the schema. The same goes for a type derived from a runtime value, such as `(typeof ROLES)[number]`: the value is its source of truth. ## Verification - Preserve the existing public contract unless a breaking change is intentional. - Add or update tests around behavior and failure paths. - Verify in order, narrowest first: the tests closest to the change, then the wider test suite, then workspace-wide type checking and linting, then the Sonar analysis. Fix any new Sonar issue on the changed code, and don't silence one without a stated reason. Run formatting before finishing. - Keep comments focused on why a non-obvious decision exists, not on repeating what the code says. ## Applying these rules in other languages The examples above are TypeScript. Apply the intent using the target language's idioms, and let the existing codebase's conventions win where they conflict: - **Exhaustive mappers** — where the type system can't enforce exhaustiveness (e.g. Go), use a `map[Kind]T` plus a test that asserts every known value has an entry, or an exhaustiveness linter such as `exhaustive`. - **`const` over `let`** — in languages without that distinction, assign each variable once; extract a function instead of reassigning across branches. - **`Result` values** — use the language's native error convention (e.g. Go's `(T, error)`), not a custom `Result` type. - **Named constants** — follow the language's naming style (`maxRetryCount` in Go, `MAX_RETRY_COUNT` in TypeScript/Python).
View on GitHub