Skip to main content

code-designing

FORWARD view over rules/ — domain type design and architectural planning for TypeScript + React code BEFORE it exists. Use when planning new features, designing self-validating types, preventing primitive obsession, or when refactoring reveals need for new types. Dispatches into the Design guidance sections of rules/R1-R8 and R10-R12.

Quellinformationen

Repository
buzzdan/ai-coding-rules
Letzte Quellaktivität
6. Oktober 2026 um 18:13
Erkannte Sprache von SKILL.md
Englisch
Sterne
7
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
code-designing
description
FORWARD view over rules/ — domain type design and architectural planning for TypeScript + React code BEFORE it exists. Use when planning new features, designing self-validating types, preventing primitive obsession, or when refactoring reveals need for new types. Dispatches into the Design guidance sections of rules/R1-R8 and R10-R12.
allowed-tools
["Skill(ts-react-linter-driven-development:testing)"]
<objective> The design phase applied BEFORE code exists. This skill is a thin directional view: every design principle lives exactly once in `../../rules/` — this protocol says which rule to open at which design step, and what shape the output takes. Backward counterpart (fixing code that already fails lint/review): @refactoring. </objective> <skill_invocation> **CRITICAL**: When this skill says "Use @skill-name", you MUST invoke it with the **Skill tool** — do not just mention it. | Notation | Skill Tool Call | |----------|-----------------| | @testing | `Skill(ts-react-linter-driven-development:testing)` | </skill_invocation> <when_to_use> - Planning a new feature (before writing code) - Refactoring reveals need for new types (@refactoring escalates here) - Linter failures that need a design decision, not a mechanical fix: - `max-params` (>4 parameters) → design a `readonly` props or options type of the parameters that travel together (score it per `../../rules/R1-primitive-obsession.md`); an object parameter typed inline at the signature tidies the call sites but leaves the clump - a tuple return (`[T, boolean]`, `[Data, Error]`), or a `Record<string, string>`, `string[]` or `Map` of primitives returned or accepted across a function boundary → the same named result type, with no ESLint rule to say so (R1, Name the Container) - `sonarjs/cognitive-complexity` or `sonarjs/max-lines-per-function` on a component, or `react/no-unstable-nested-components` → the component is the fat function: design the hook and the leaf type it should be reading (per `../../rules/R3-storifying.md`), not a smaller component nested inside it - the same `switch` on one discriminant in a second file, or `@typescript-eslint/no-explicit-any` at a boundary → design the discriminated union and its one dispatch owner (`../../rules/R11-conditional-dispatch.md`), or the parser that builds the type from `unknown` (`../../rules/R2-self-validating-types.md`) - `sonarjs/max-lines` (600; or a module over ~450 lines where the repository sets no limit — count) → split juicy types into their own modules (juiciness per R1; module-per-type per `../../rules/R5-vertical-slice.md`); a single god component or class routes to @refactoring's god-object decomposition procedure first - Package-size yellow/red zone → re-model with sub-folders *before* the zone escalates (`<package_decomposition>` in @refactoring's `reference.md` (`sed -n '/^<package_decomposition>/,/^<\/package_decomposition>/p; /^### Package decomposition/,$p'`)) - A Phase 4 review CLUSTER (≥2 hunters converging on one anchor — @linter-driven-development routes it here) → **cluster-scoped mode**: skip `<architecture_scan>` and the user-OK step (acceptance was inherited when the findings were accepted); design only the one concept the cluster names — its type or dispatch shape (R11), constructor (R2), mutation surface (R12), and placement (R4) — so every member finding resolves as a consequence of that one design. Return the mini DESIGN PLAN to the caller; @refactoring implements it. </when_to_use> <protocol> <architecture_scan priority="FIRST_STEP"> **Default: vertical slice architecture** — `../../rules/R5-vertical-slice.md`. Scan the codebase structure: vertical (`pages/<Page>/` holding the page's components, hooks, api module, types and tests — one folder per feature) vs horizontal (top-level `components/`, `hooks/`, `services/`, `types/`, each holding one slice of every feature)? 1. **Pure vertical** → continue the pattern: implement as `internal/<new-feature>/`. 2. **Pure horizontal** → propose starting migration (template in R5's Design guidance); implement the new feature as the first vertical slice. 3. **Mixed** → check `docs/architecture/vertical-slice-migration.md`, continue as a slice. Architecture advises, it doesn't veto (R5's advisory posture). Ask the user: Option A — vertical slice (recommended); Option B — match the existing pattern (time pressure and team conventions are valid reasons). </architecture_scan> <understand_domain> What is the problem domain? The main concepts/entities? The invariants and rules? How does this fit the existing architecture? </understand_domain> <maxim_interrogation> Design happens before a diff exists — no detection command can run yet, so questions are the tool. Interrogate the plan with `../../maxims.md` (the questions live there, once; ask them, don't restate them): - Every function that receives another type's data → **Tell, don't ask**: does the decision it makes belong on that type? - Every planned interface → **The bigger the interface, the weaker the abstraction**: could it be one method? - Every planned type → **Make illegal states unrepresentable** vs **Make the zero value useful**: validated domain type (constructor) or mechanism type (useful zero)? Pick a family. - Every planned check → **Parse, don't validate**: does it return a more-typed value or a boolean someone must remember? - Every planned signature that returns or accepts a container of primitives → **Tell, don't ask**: what will the receiver do with it? Each operation is a method of a type that does not exist yet (`../../rules/R1-primitive-obsession.md`, "Containers of primitives"). - Every shared helper → **A little copying is better than a little dependency**: is the third strike actually here? Answers shape the plan; they are never findings. Maxims propose, evidence disposes — the review phases convict only via rules (`maxims.md`, contract section). </maxim_interrogation> <rule_dispatch> For each concept in the design, open the rule that owns the question and apply its **Design guidance** section: | Rule | When designing, apply... | |------|--------------------------| | `../../rules/R1-primitive-obsession.md` | Which primitives become types — score every candidate with R1's juiciness scorecard; reject ceremony wrappers (over-abstraction trap). | | `../../rules/R2-self-validating-types.md` | Constructor-only entry, validation ownership, trusting composed values, undefined is not a value, no defensive checks in methods. | | `../../rules/R3-storifying.md` | Plan orchestration functions as 3–5 named steps at one conceptual level; honest names for mutators. | | `../../rules/R4-helper-placement.md` | WHERE each helper/type lands — the placement ladder (internal → feature sub-package → shared domain package). | | `../../rules/R5-vertical-slice.md` | Package structure and naming: feature slices with roles inside, flatcase domain vocabulary, migration template. | | `../../rules/R6-test-only-interfaces.md` | Default dependencies to concrete types; an interface must be earned by a second production implementation or a grep-verified import cycle. | | `../../rules/R7-test-placement.md` | The test plan per type: leaf types 100% unit coverage via public constructors, checked by a mutation run over the leaf's package; orchestrators integration-tested over real collaborators, never mutated. | | `../../rules/R8-no-globals.md` | Dependencies injected via constructors, cancellation passed down from callers, globals only at entry points. | | `../../rules/R10-concurrency-safety.md` | Every planned async task gets an owner (stop + wait) and an exit path at construction time; shared state designed with its guard on one type — or designed away via handoff/confinement. | | `../../rules/R11-conditional-dispatch.md` | How each kind/variant family dispatches: behavior-heavy or open set → interface chosen once at the boundary; single-behavior variance → strategy map; single-site closed enum → one exhaustive switch (named enum per R1). | | `../../rules/R12-mutation-discipline.md` | Each type's mutation surface: constructors copy slice/map arguments; queries return copies or iterators, never internal references; no setters around validating constructors; query and modifier as separate methods. | </rule_dispatch> <design_checklist> Before presenting the plan, verify against the rules (cite, don't restate): - [ ] No primitive obsession; every proposed type scored, ceremony rejected (R1) - [ ] Every planned signature names its types: no nested container, no flat container of primitives crossing a function boundary that its receivers operate on; a product result has a name and field names (R1, Name the Container) - [ ] Types are self-validating; composed types trusted, never re-validated (R2) - [ ] Orchestration planned as a story; most logic pushed into leaf types (R3, R7) - [ ] **Placement decided** for every helper and type via the ladder — internal helper vs feature sub-package vs domain package (`../../rules/R4-helper-placement.md`) - [ ] Vertical slice structure; package names are flatcase domain vocabulary, never roles/containers (R5) - [ ] No test-only interfaces: every interface has a second production implementation OR breaks a real import cycle, verified by grepping the import direction (detection command in `../../rules/R6-test-only-interfaces.md`); otherwise depend on the concrete type - [ ] Import direction strictly downward: leaf types ← sub-packages ← parent ← cmd/ (cycle-breaking move in `<package_decomposition>` in @refactoring's `reference.md` (`sed -n '/^<package_decomposition>/,/^<\/package_decomposition>/p; /^### Package decomposition/,$p'`)) - [ ] Dependencies constructor-injected and validated; cancellation flows down; no new globals (R8, R2) - [ ] Every async task has an owner and exit path; shared state guarded where it lives, or confined (R10) - [ ] Every kind/variant family has ONE dispatch owner — interface, strategy map, or a single exhaustive switch; no discriminator inspected in two places (R11) - [ ] Every validated type's mutation surface is closed: slice/map arguments copied in, internal collections never returned by reference, no unvalidated setters (R12) </design_checklist> </protocol> <output_format> ``` DESIGN PLAN Feature: [Feature Name] Core Domain Types (leaf): - [Type] ([underlying]) — invariant it owns; juiciness verdict (R1) - [Type] — the container it names and the receiver operations that become its methods (R1, Name the Container) Orchestrating Types: - [Type] — dependencies (concrete unless R6-justified), methods Package Structure: pages/Snapshots/ ├── index.ts # the public surface: what another page imports ├── SnapshotsPage.tsx # the component: its render tree is the story ├── useSnapshots.ts # the hook: the query and state the page reads ├── snapshotsApi.ts # the api module: fetch and parse at the boundary ├── snapshot.ts # each juicy type in its own module (Snapshot, parseSnapshot) └── SnapshotsPage.test.tsx Placement Decisions (R4): - [helper/type] → rung 1/2/3 and why Design Decisions: - [decision] — rationale, citing the owning rule Integration Points: - Consumed by / depends on / events Next Steps: 1. Create types with validating constructors 2. Write unit tests for each leaf type → use @testing skill 3. Implement orchestrators; integration tests over real collaborators ``` </output_format> <success_criteria> Design phase is complete when ALL are true: - [ ] Architecture pattern analyzed (vertical/horizontal/mixed) and user chose an option - [ ] Core domain types identified, each with its validation rules and R1 score - [ ] Placement decision recorded for every new type/helper (R4 ladder) - [ ] Package structure follows R5 (slices, naming, downward imports) - [ ] Design checklist answered satisfactorily (every box cites its rule) - [ ] Design plan presented in the output format above </success_criteria>
Auf GitHub ansehen