Communitygithub.com

코딩 표준

네이밍, 가독성, 불변성, 코드 품질 리뷰를 위한 프로젝트 전반의 기본 코딩 규칙입니다. 프레임워크별 패턴이 필요할 때는 상세한 프론트엔드 또는 백엔드 스킬을 사용하세요. 특정 프레임워크 스킬이 적용되지 않는 코드 품질 리뷰나 네이밍 검토 시 활성화합니다.

코딩 표준란 무엇인가요?

이 스킬은 프로젝트 전반에 걸쳐 일관된 코딩 표준과 모범 사례를 시행하는 기본 규칙 레이어를 제공합니다. 네이밍 규칙, 불변성, 가독성(KISS, DRY, YAGNI) 및 코드 스멜 감지에 중점을 둡니다. 'coding-standards'는 프레임워크별 지침의 기초 역할을 하며, React 패턴은 'frontend-patterns'를, 백엔드 아키텍처는 'backend-patterns' 또는 'api-design' 스킬을 참조해야 합니다. TypeScript/JavaScript 표준, React 모범 사례, API 설계 규칙, 파일 조직 및 테스트 전략에 대한 실행 가능한 예제를 제공합니다. 이 스킬은 AI 코딩 어시스턴트(Claude Code, Cursor, Codex 등)에서 사용되며, 리뷰 중에 코드 품질 규칙을 자동으로 적용하거나 새 프로젝트를 초기화할 때 유용합니다. 코드 리뷰, 리팩토링 및 신규 기여자 온보딩 중에 활성화하는 것이 좋습니다.

지원 대상~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/coding-standards

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

코딩 표준 및 모범 사례

프로젝트 전반에 적용되는 기본 코딩 규칙입니다.

이 스킬은 공유되는 기본 규칙이며, 상세한 프레임워크 플레이북이 아닙니다.

  • React, 상태, 폼, 렌더링 및 UI 아키텍처에는 frontend-patterns를 사용하세요.
  • 저장소/서비스 계층, 엔드포인트 설계, 유효성 검사 및 서버별 문제에는 backend-patterns 또는 api-design을 사용하세요.
  • 전체 스킬 워크스루 대신 가장 짧은 재사용 가능한 규칙 레이어가 필요할 때는 rules/common/coding-style.md를 사용하세요.

활성화 시점

  • 새 프로젝트 또는 모듈을 시작할 때
  • 코드 품질 및 유지보수성을 리뷰할 때
  • 기존 코드를 규칙에 맞게 리팩토링할 때
  • 네이밍, 포맷팅 또는 구조적 일관성을 적용할 때
  • 린팅, 포맷팅 또는 타입 검사 규칙을 설정할 때
  • 새 기여자에게 코딩 규칙을 온보딩할 때

범위 경계

이 스킬을 다음에 활성화하세요:

  • 설명적인 네이밍
  • 불변성 기본 설정
  • 가독성, KISS, DRY, YAGNI 적용
  • 오류 처리 기대치 및 코드 스멜 리뷰

다음의 경우 이 스킬을 주요 출처로 사용하지 마세요:

  • React 구성, 훅 또는 렌더링 패턴
  • 백엔드 아키텍처, API 설계 또는 데이터베이스 계층
  • 더 좁은 범위의 ECC 스킬이 이미 존재하는 도메인별 프레임워크 지침

코드 품질 원칙

1. 가독성 우선

  • 코드는 작성되는 것보다 더 많이 읽힙니다
  • 명확한 변수 및 함수 이름
  • 주석보다는 자체 문서화 코드 선호
  • 일관된 포맷팅

2. KISS (Keep It Simple, Stupid)

  • 작동하는 가장 간단한 해결책
  • 과도한 엔지니어링 지양
  • 섣부른 최적화 금지
  • 이해하기 쉬운 코드 > 영리한 코드

3. DRY (Don't Repeat Yourself)

  • 공통 로직을 함수로 추출
  • 재사용 가능한 컴포넌트 생성
  • 모듈 간 유틸리티 공유
  • 복사-붙여넣기 프로그래밍 지양

4. YAGNI (You Aren't Gonna Need It)

  • 필요해지기 전에 기능을 만들지 마세요
  • 추측성 일반화 지양
  • 필요할 때만 복잡성 추가
  • 간단하게 시작하고 필요할 때 리팩토링

TypeScript/JavaScript 표준

변수 네이밍

// PASS: 좋음: 설명적인 이름
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000

// FAIL: 나쁨: 불명확한 이름
const q = 'election'
const flag = true
const x = 1000

함수 네이밍

// PASS: 좋음: 동사-명사 패턴
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }

// FAIL: 나쁨: 불명확하거나 명사만 있음
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }

불변성 패턴 (매우 중요)

// PASS: 항상 spread 연산자 사용
const updatedUser = {
  ...user,
  name: 'New Name'
}

const updatedArray = [...items, newItem]

// FAIL: 직접 변형 금지
user.name = 'New Name'  // 나쁨
items.push(newItem)     // 나쁨

오류 처리

// PASS: 좋음: 포괄적인 오류 처리
async function fetchData(url: string) {
  try {
    const response = await fetch(url)

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }

    return await response.json()
  } catch (error) {
    console.error('Fetch failed:', error)
    throw new Error('Failed to fetch data')
  }
}

// FAIL: 나쁨: 오류 처리 없음
async function fetchData(url) {
  const response = await fetch(url)
  return response.json()
}

Async/Await 모범 사례

// PASS: 좋음: 가능한 경우 병렬 실행
const [users, markets, stats] = await Promise.all([
  fetchUsers(),
  fetchMarkets(),
  fetchStats()
])

// FAIL: 나쁨: 필요 없는데 순차 실행
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()

타입 안전성

// PASS: 좋음: 적절한 타입
interface Market {
  id: string
  name: string
  status: 'active' | 'resolved' | 'closed'
  created_at: Date
}

function getMarket(id: string): Promise<Market> {
  // 구현
}

// FAIL: 나쁨: 'any' 사용
function getMarket(id: any): Promise<any> {
  // 구현
}

React 모범 사례

컴포넌트 구조

// PASS: 좋음: 타입이 있는 함수형 컴포넌트
interface ButtonProps {
  children: React.ReactNode
  onClick: () => void
  disabled?: boolean
  variant?: 'primary' | 'secondary'
}

export function Button({
  children,
  onClick,
  disabled = false,
  variant = 'primary'
}: ButtonProps) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`btn btn-${variant}`}
    >
      {children}
    </button>
  )
}

// FAIL: 나쁨: 타입 없음, 구조 불명확
export function Button(props) {
  return <button onClick={props.onClick}>{props.children}</button>
}

커스텀 훅

// PASS: 좋음: 재사용 가능한 커스텀 훅
export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value)

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    return () => clearTimeout(handler)
  }, [value, delay])

  return debouncedValue
}

// 사용법
const debouncedQuery = useDebounce(searchQuery, 500)

상태 관리

// PASS: 좋음: 적절한 상태 업데이트
const [count, setCount] = useState(0)

// 이전 상태 기반 함수형 업데이트
setCount(prev => prev + 1)

// FAIL: 나쁨: 직접 상태 참조
setCount(count + 1)  // 비동기 시나리오에서 오래된 값 가능

조건부 렌더링

// PASS: 좋음: 명확한 조건부 렌더링
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}

// FAIL: 나쁨: 삼항 연산자 지옥
{isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}

API 설계 표준

REST API 규칙

GET    /api/markets              # 모든 시장 목록
GET    /api/markets/:id          # 특정 시장 조회
POST   /api/markets              # 새 시장 생성
PUT    /api/markets/:id          # 시장 업데이트 (전체)
PATCH  /api/markets/:id          # 시장 업데이트 (부분)
DELETE /api/markets/:id          # 시장 삭제

# 필터링을 위한 쿼리 파라미터
GET /api/markets?status=active&limit=10&offset=0

응답 형식

// PASS: 좋음: 일관된 응답 구조
interface ApiResponse<T> {
  success: boolean
  data?: T
  error?: string
  meta?: {
    total: number
    page: number
    limit: number
  }
}

// 성공 응답
return NextResponse.json({
  success: true,
  data: markets,
  meta: { total: 100, page: 1, limit: 10 }
})

// 오류 응답
return NextResponse.json({
  success: false,
  error: 'Invalid request'
}, { status: 400 })

입력 유효성 검사

import { z } from 'zod'

// PASS: 좋음: 스키마 유효성 검사
const CreateMarketSchema = z.object({
  name: z.string().min(1).max(200),
  description: z.string().min(1).max(2000),
  endDate: z.string().datetime(),
  categories: z.array(z.string()).min(1)
})

export async function POST(request: Request) {
  const body = await request.json()

  try {
    const validated = CreateMarketSchema.parse(body)
    // 검증된 데이터로 진행
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json({
        success: false,
        error: 'Validation failed',
        details: error.issues
      }, { status: 400 })
    }
  }
}

파일 조직

프로젝트 구조

src/
├── app/                    # Next.js App Router
│   ├── api/               # API 라우트
│   ├── markets/           # 시장 페이지
│   └── (auth)/           # 인증 페이지 (라우트 그룹)
├── components/            # React 컴포넌트
│   ├── ui/               # 일반 UI 컴포넌트
│   ├── forms/            # 폼 컴포넌트
│   └── layouts/          # 레이아웃 컴포넌트
├── hooks/                # 커스텀 React 훅
├── lib/                  # 유틸리티 및 설정
│   ├── api/             # API 클라이언트
│   ├── utils/           # 헬퍼 함수
│   └── constants/       # 상수
├── types/                # TypeScript 타입
└── styles/              # 전역 스타일

파일 네이밍

components/Button.tsx          # 컴포넌트는 PascalCase
hooks/useAuth.ts              # 'use' 접두사와 camelCase
lib/formatDate.ts             # 유틸리티는 camelCase
types/market.types.ts         # .types 접미사와 camelCase

주석 및 문서

주석을 달아야 할 때

// PASS: 좋음: 무엇이 아닌 왜를 설명
// API 중단 중 과부하를 방지하기 위해 지수 백오프 사용
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)

// 대규모 배열 성능을 위해 의도적으로 변형 사용
items.push(newItem)

// FAIL: 나쁨: 자명한 것 설명
// 카운터를 1 증가
count++

// 이름을 사용자 이름으로 설정
name = user.name

공개 API용 JSDoc

/**
 * 시맨틱 유사도를 사용하여 시장을 검색합니다.
 *
 * @param query - 자연어 검색 쿼리
 * @param limit - 최대 결과 수 (기본값: 10)
 * @returns 유사도 점수로 정렬된 시장 배열
 * @throws {Error} OpenAI API 실패 또는 Redis 사용 불가 시
 *
 * @example
 * ```typescript
 * const results = await searchMarkets('election', 5)
 * console.log(results[0].name) // "Trump vs Biden"
 * ```
 */
export async function searchMarkets(
  query: string,
  limit: number = 10
): Promise<Market[]> {
  // 구현
}

성능 모범 사례

메모이제이션

import { useMemo, useCallback } from 'react'

// PASS: 좋음: 비용이 많이 드는 계산 메모이제이션
const sortedMarkets = useMemo(() => {
  return [...markets].sort((a, b) => b.volume - a.volume)
}, [markets])

// PASS: 좋음: 콜백 메모이제이션
const handleSearch = useCallback((query: string) => {
  setSearchQuery(query)
}, [])

지연 로딩

import { lazy, Suspense } from 'react'

// PASS: 좋음: 무거운 컴포넌트 지연 로딩
const HeavyChart = lazy(() => import('./HeavyChart'))

export function Dashboard() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyChart />
    </Suspense>
  )
}

데이터베이스 쿼리

// PASS: 좋음: 필요한 컬럼만 선택
const { data } = await supabase
  .from('markets')
  .select('id, name, status')
  .limit(10)

// FAIL: 나쁨: 모든 것 선택
const { data } = await supabase
  .from('markets')
  .select('*')

테스트 표준

테스트 구조 (AAA 패턴)

test('유사도를 올바르게 계산한다', () => {
  // Arrange (준비)
  const vector1 = [1, 0, 0]
  const vector2 = [0, 1, 0]

  // Act (실행)
  const similarity = calculateCosineSimilarity(vector1, vector2)

  // Assert (검증)
  expect(similarity).toBe(0)
})

테스트 네이밍

// PASS: 좋음: 설명적인 테스트 이름
test('쿼리와 일치하는 시장이 없으면 빈 배열을 반환한다', () => { })
test('OpenAI API 키가 없으면 오류를 던진다', () => { })
test('Redis를 사용할 수 없을 때 부분 문자열 검색으로 폴백한다', () => { })

// FAIL: 나쁨: 모호한 테스트 이름
test('작동한다', () => { })
test('검색 테스트', () => { })

코드 스멜 탐지

다음 안티 패턴을 주의하세요:

1. 긴 함수

// FAIL: 나쁨: 50줄이 넘는 함수
function processMarketData() {
  // 100줄의 코드
}

// PASS: 좋음: 더 작은 함수로 분할
function processMarketData() {
  const validated = validateData()
  const transformed = transformData(validated)
  return saveData(transformed)
}

2. 깊은 중첩

// FAIL: 나쁨: 5단계 이상의 중첩
if (user) {
  if (user.isAdmin) {
    if (market) {
      if (market.isActive) {
        if (hasPermission) {
          // 작업 수행
        }
      }
    }
  }
}

// PASS: 좋음: 조기 반환
if (!user) return
if (!user.isAdmin) return
if (!market) return
if (!market.isActive) return
if (!hasPermission) return

// 작업 수행

3. 매직 넘버

// FAIL: 나쁨: 설명 없는 숫자
if (retryCount > 3) { }
setTimeout(callback, 500)

// PASS: 좋음: 이름이 있는 상수
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500

if (retryCount > MAX_RETRIES) { }
setTimeout(callback, DEBOUNCE_DELAY_MS)

기억하세요: 코드 품질은 타협할 수 없습니다. 명확하고 유지보수 가능한 코드는 빠른 개발과 자신 있는 리팩토링을 가능하게 합니다.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

관련 스킬