Skip to main content

audit-code-quality

Detect and fix repo-wide anti-patterns and consistency drift (naming, organisation, repeated smells). Use when "code smell", "anti-pattern", "technical debt", or "standardize the codebase". This PR/diff review → audit-code-review.

소스 정보

저장소
kensaurus/cursor-kenji
최근 소스 활동
2026년 8월 28일 22:39
감지된 SKILL.md 언어
영어
스타
9
포크
0

설치 방법

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

소스 파일 검토

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

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
audit-code-quality
description
Detect and fix repo-wide anti-patterns and consistency drift (naming, organisation, repeated smells). Use when "code smell", "anti-pattern", "technical debt", or "standardize the codebase". This PR/diff review → audit-code-review.
license
MIT
# Code Quality Audit **Degree of freedom: MIXED** — Parts 1–2 judgment `[HIGH freedom]`; convention greps and Validation `[LOW freedom — run exactly]`. > **Audit-and-fix exception.** Detect and then fix. Not present-then-stop. Repo-wide React/TypeScript anti-patterns plus naming, organisation, and pattern consistency. A named PR/diff → `audit-code-review`. ## How to reason 1. **Observe** — quote the smell (`file:line`) and whether `git blame` / CONTRIBUTING marks it intentional 2. **Interpret** — bug/perf risk, or style-only drift? 3. **Classify** — anti-pattern / naming / organisation / pattern-split / intentional 4. **Severity** — runtime bug or data-fetch `useEffect` = High; naming-only = Low ## Worked example > **Observe:** `components/PaymentForm.tsx` has `'use server'` and a > `useEffect` that fetches invoices; four sortable lists use `key={i}`. > **Interpret:** server action lives in UI; fetch refires on remount; reorder remounts rows. > **Classify:** organisation + `useEffect`-for-data + index-as-key. > **Severity:** High (actions-in-components); Medium (keys). > **Finding:** `PaymentForm.tsx` | High | move action to `features/*/server/`; > replace fetch effect with TanStack Query ## Before any change [LOW freedom — run exactly] ```bash cat CONTRIBUTING.md .cursor/rules/*.md 2>/dev/null | head -100 # existing conventions git log --oneline -20 | grep -i "convention\|pattern\|style" # recent decisions ``` Verify the "inconsistency" isn't intentional. Check `git blame` before touching working code. --- ## Part 1 — Anti-patterns [HIGH freedom] ### React #### Props drilling → Context or composition ```tsx // Bad: prop drilled through 5+ levels <Layout user={user}><Sidebar user={user}><UserMenu user={user}><Avatar user={user} /> // Fix: context for global state const UserContext = createContext<User | null>(null) const useUser = () => useContext(UserContext) // Fix: composition for UI concerns <Layout><Layout.Sidebar><UserMenu /></Layout.Sidebar></Layout> ``` #### Derived state in `useState` → `useMemo` ```tsx // Bad const [items, setItems] = useState([]) const [filtered, setFiltered] = useState([]) useEffect(() => { setFiltered(items.filter(i => i.active)) }, [items]) // Fix const filtered = useMemo(() => items.filter(i => i.active), [items]) ``` #### `useEffect` for data fetching → Server Components or TanStack Query ```tsx // Fix (Next.js 16 Server Component) async function DataDisplay() { const data = await db.getData() return <div>{data.name}</div> } // Fix (client with TanStack Query) const { data, isLoading } = useQuery({ queryKey: ['data'], queryFn: fetchData }) ``` #### Object/array in dependency array → memoize or destructure ```tsx // Bad: new object every render → infinite loop useEffect(() => { doSomething(options) }, [options]) // Fix const options = useMemo(() => ({ page, limit }), [page, limit]) useEffect(() => { doSomething(options) }, [options]) ``` #### Index as key in dynamic lists → stable IDs ```tsx // Bad {items.map((item, i) => <Item key={i} />)} // Fix {items.map(item => <Item key={item.id} />)} ``` #### Giant component → composition ```tsx // Split by responsibility export function UserDashboard() { const user = useUser() return ( <DashboardLayout> <UserHeader user={user} /> <UserStats userId={user.id} /> <RecentActivity userId={user.id} /> </DashboardLayout> ) } ``` ### TypeScript ```tsx // Bad: any function processData(data: any) { return data.items.map((i: any) => i.name) } // Fix: proper types + Zod validation const DataSchema = z.object({ items: z.array(z.object({ id: z.string(), name: z.string() })) }) function processData(data: z.infer<typeof DataSchema>) { return data.items.map(i => i.name) } // Bad: enums (runtime object, not tree-shakeable) enum Status { Pending = 'pending', Active = 'active' } // Fix: union types type Status = 'pending' | 'active' // Fix: exhaustive switch function handle(s: Status): string { switch (s) { case 'pending': return 'Waiting' case 'active': return 'Running' default: const _: never = s throw new Error(`Unknown: ${_}`) } } ``` ### State management ```tsx // Rule of thumb: // URL state (nuqs) → shareable, bookmarkable // Global state (Zustand) → cross-component, persisted // Local state (useState) → component-specific, ephemeral // Stale closure fix useEffect(() => { const id = setInterval(() => setCount(c => c + 1), 1000) // functional update return () => clearInterval(id) }, []) ``` ### Architecture ``` // Circular deps → extract shared code / dependency inversion // Business logic in components → move to lib/feature/calculations.ts // God files → feature-based organisation: lib/ date/format.ts currency/format.ts validation/schemas.ts ``` --- ## Part 2 — Consistency audit [HIGH freedom; greps LOW] ### Naming conventions | Element | Expected | Check | |---------|----------|-------| | Components | PascalCase | `userCard` vs `UserCard` | | Hooks | `use` prefix | `fetchData` vs `useFetchData` | | Utils | camelCase | `format_date` vs `formatDate` | | Constants | SCREAMING_SNAKE | `apiUrl` vs `API_URL` | | Files | kebab-case | `UserCard.tsx` vs `user-card.tsx` | | Boolean props | `is/has/should` | `loading` vs `isLoading` | ```bash rg "export (function|const|class) [a-z]" --type tsx # lowercase component exports rg "use[A-Z]" --type ts # hook patterns rg "export default" --type tsx -l | head -20 # mixed default/named exports ``` ### File organisation (feature-sliced) ``` src/ features/{name}/ components/ # UI only hooks/ # custom hooks server/ # server actions types.ts schemas.ts components/ui/ # shared primitives lib/ # global utilities ``` Red flags: - Components in `/lib` or `/utils` - Server actions in component files - Types scattered across component files - Zod schemas inline in components ```bash rg "z\.object" --glob "*/components/*" # inline schemas rg "'use server'" --glob "*/components/*" # actions in wrong place rg "from '\.\." --type tsx | head -20 # relative imports instead of @/ ``` ### Pattern consistency | Concern | Check | |---------|-------| | Server state | All TanStack Query, or mixed with useEffect? | | Forms | All React Hook Form, or controlled inputs too? | | Error handling | Consistent ActionResult shape? | | Styling | cn() used everywhere? Dark mode via CSS vars? | | Tests | `*.test.ts` vs `__tests__/`? Consistent mocking? | --- ## Coherency report template ```markdown # Code Quality Audit ## Summary - Overall score: X/10 - Critical findings: X ## Anti-patterns found | Pattern | Files | Severity | |---------|-------|----------| | useEffect for data | 3 files | High | | Index as key | 2 files | Medium | ## Naming convention findings | Element | Expected | Actual | Files | |---------|----------|--------|-------| | Components | PascalCase | Mixed | 4 | ## Organisation findings - Server actions found in: components/PaymentForm.tsx - Types scattered in: 6 component files ## Priority fixes 1. Move server actions to features/*/server/ 2. Replace useEffect data fetching with TanStack Query 3. Standardise component naming to PascalCase ## Conventions to document 1. Decision on default vs named exports 2. Where Zod schemas live ``` --- ## Anti-pattern detection checklist ### React - [ ] No `useEffect` for derived state - [ ] No index keys in dynamic lists - [ ] No objects/arrays in dependency arrays - [ ] Components under 300 lines - [ ] No prop drilling beyond 2 levels ### TypeScript - [ ] No `any` (use `unknown` + validation) - [ ] No unsafe type assertions - [ ] Exhaustive switch statements - [ ] Zod schemas for all external data ### Architecture - [ ] No circular dependencies - [ ] Business logic separated from UI - [ ] Files under 400 lines - [ ] Clear module boundaries ## Self-critique before applying fixes [LOW freedom — do not skip] 1. **Evidenced** — `file:line` or rg hit, not "the codebase feels messy" 2. **Reproducible** — the convention grep still finds it 3. **Severity justified** — High = bug/perf, not naming taste 4. **Right owner** — this PR/diff → `audit-code-review` 5. **No-false-safety** — `git blame` checked; working intentional code left alone ## Validation [LOW freedom — run exactly] 1. Run TypeScript strict: `npx tsc --noEmit` 2. Run linter: `npx eslint src/` 3. Confirm no regressions: `npx vitest run` 4. Document any enforced standard in `CONTRIBUTING.md` or `.cursor/rules/`
GitHub에서 보기