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.

소스 정보

저장소
buzzdan/ai-coding-rules
최근 소스 활동
2026년 10월 6일 18:13
감지된 SKILL.md 언어
영어
스타
7
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
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>
GitHub에서 보기