오늘만 무료

CLAUDE.md 완전 정복 - 코딩 규약 작성법

AI가 팀 컨벤션을 100% 따르게 만드는 법

by AI개발자
CLAUDE.md 완전 정복.png

CLAUDE.md에서 가장 자주 업데이트하게 되는 섹션이 코딩 규약입니다.

"Claude Code에 이렇게 작성해 달라"는 규칙을 하나씩 추가해 나갈수록 출력 품질이 조금씩, 그러나 확실하게 높아집니다.


이 장에서는 언어·프레임워크별로 바로 복붙해서 쓸 수 있는 코딩 규약 예시와, 규약을 잘 작성하는 원칙을 소개합니다.



규약을 작성할 때의 3가지 원칙

원칙 1. 구체적으로 작성한다

"깔끔한 코드를 작성한다"는 너무 모호합니다. AI는 이 문장을 보고 나름의 기준으로 해석하는데, 그 결과가 항상 여러분의 의도와 일치하지 않습니다. 구체적인 수치나 조건으로 풀어서 작성하세요.

# ❌ 모호한 작성 방식
- 깔끔한 코드를 작성한다
- 적절한 에러 핸들링을 한다

# ✅ 구체적인 작성 방식
- 함수는 30행 이내로 작성한다. 초과하는 경우에는 책임에 따라 분할한다
- 외부 API 호출은 try-catch로 감싸고, 에러는 AppError 클래스로 래핑한 뒤 상위로 전파한다

원칙 2. 선택지를 없앤다

"A 또는 B 중 어느 쪽이든 괜찮다"는 식의 모호함을 남기면 AI의 출력이 매 번 달라집니다. 하나를 선택해 강제하세요.

# ❌ 모호한 방식
- interface 또는 type으로 타입을 정의한다

# ✅ 명확한 방식
- 타입 정의에는 type을 사용한다. interface는 사용하지 않는다

팀 내에서 아직 합의가 안 된 사항이라도, 일단 하나를 골라 CLAUDE.md에 명시해 두는 편이 낫습니다. AI의 출력이 일관되어야 코드 리뷰 부담이 줄어듭니다.


원칙 3. 예외를 명시한다

모든 규칙에는 예외가 있습니다. 예외를 명시하지 않으면 AI가 규칙을 기계적으로 적용해 오히려 역효과가 나는 경우가 생깁니다.

- 변수명은 영어로 작성한다. 단, 국제화(i18n) 키에는 한국어를 포함해도 된다
- any 타입은 사용하지 않는다. 단, 외부 라이브러리의 타입 정의가 불완전한 경우는
`// eslint-disable-next-line @typescript-eslint/no-explicit-any` 주석을 붙여 허용
- console.log는 사용하지 않는다. 단, 개발 서버 진단용 코드에는 `// TODO: remove` 주석 필수


TypeScript 규약 샘플

## TypeScript 규약

### 타입
- `strict: true`를 전제로 한다
- 타입 정의는 `type`을 사용한다. `interface`는 외부 라이브러리와의 호환성이 필요한 경우에만 사용
- `any`는 금지. `unknown`을 사용하고, 타입 가드로 좁힌다
- 유니온 타입은 3개까지. 그 이상은 Discriminated Union 패턴을 사용한다
- 제네릭 타입 파라미터명: 단일 문자(`T`)보다 의미 있는 이름 사용 (`TData`, `TError`)

### 명명
- 변수·함수: camelCase
- 타입·클래스·컴포넌트: PascalCase
- 상수: UPPER_SNAKE_CASE (파일 스코프 상수에만)
- boolean 변수: `is`, `has`, `can`, `should` 접두사
- 이벤트 핸들러: `handle` 접두사 (예: `handleSubmit`, `handleChange`)

### 함수
- 순수 함수를 우선한다. 부작용이 있는 함수는 이름에 명시한다 (`saveUser`, `deleteFile`)
- 인수가 3개 이상이면 객체 인수로 만든다
- 반환값 타입은 생략하지 않고 명시한다
- 비동기 함수는 `async/await`를 사용한다. `.then()` 체이닝은 사용하지 않는다

### 임포트
- 상대 경로는 `@/` 별칭을 사용한다 (`../../../components` 금지)
- 미사용 import는 허용하지 않는다
- 타입만의 임포트는 `import type`을 사용한다
- 임포트 순서: 외부 라이브러리 → 내부 모듈 → 타입 (빈 줄로 구분)


React 규약 샘플

## React 규약

### 컴포넌트
- 함수 컴포넌트만 사용한다. 클래스 컴포넌트는 사용하지 않는다
- `export default`는 사용하지 않는다. named export만 사용한다
- props 타입은 같은 파일 안에서 `type Props = { ... }`로 정의한다
- children prop이 필요한 경우는 `React.PropsWithChildren<Props>`를 사용한다
- 컴포넌트 파일 1개당 컴포넌트 1개. 여러 컴포넌트를 한 파일에 담지 않는다

### 상태 관리
- 로컬 상태: `useState` / `useReducer`
- 서버 상태: TanStack Query (SWR은 사용하지 않는다)
- 전역 상태: Zustand (꼭 필요한 경우에만, 최소한으로)
- URL 파라미터로 표현할 수 있는 상태는 URL로 관리한다 (`nuqs` 라이브러리 사용)
- 파생 상태는 `useMemo` 없이 렌더 시점에 계산한다

### 성능
- `useMemo`와 `useCallback`은 프로파일링으로 필요하다고 확인된 경우에만 사용한다
- 리스트 렌더링은 `key`에 안정적인 고유값을 사용한다 (`index` 사용 금지)
- 이미지는 `next/image`를 사용하고, `width`와 `height`를 반드시 명시한다
- 동적 임포트(`next/dynamic`)는 초기 번들 크기가 50KB를 넘는 컴포넌트에 적용한다

### 테스트
- 컴포넌트 테스트는 Testing Library를 사용한다
- `getByTestId`는 최후의 수단. `getByRole`, `getByLabelText`, `getByText`를 우선한다
- 유저 이벤트는 `@testing-library/user-event`를 사용한다 (`fireEvent` 금지)
- 스냅샷 테스트는 사용하지 않는다 (변경에 취약하고 의미가 없음)


백엔드 API 규약 샘플

## API 설계 규약

### 엔드포인트
- RESTful하게 설계한다
- 리소스명은 복수형 (`/users`, `/orders`)
- 중첩은 2계층까지 (`/users/:id/orders`는 OK, `/users/:id/orders/:orderId/items`는 NG)
- 액션은 동사가 아닌 HTTP 메서드로 표현한다 (`POST /orders`이지, `/createOrder`가 아님)
- 버전 접두사 필수: `/api/v1/...`

### 응답 형식

성공 시:
\`\`\`json
{
"data": { ... },
"meta": { "total": 100, "page": 1, "perPage": 20 }
}
\`\`\`

에러 시:
\`\`\`json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "이메일은 필수입니다",
"details": [
{ "field": "email", "message": "이메일 형식이 올바르지 않습니다" }
]
}
}
\`\`\`

### 유효성 검사
- 요청 바디는 Zod 스키마로 검증한다
- 유효성 검사 에러는 400을 반환한다
- 스키마는 `schemas/` 디렉토리에 리소스 단위로 배치한다
- 스키마는 OpenAPI 문서 자동 생성에도 활용한다

### HTTP 상태 코드
- 200: 조회·수정 성공
- 201: 생성 성공
- 204: 삭제 성공 (응답 바디 없음)
- 400: 유효성 검사 에러
- 401: 미인증 (토큰 없음 또는 만료)
- 403: 권한 부족 (인증은 됐지만 권한 없음)
- 404: 리소스 없음
- 409: 충돌 (중복 생성 등)
- 500: 서버 에러 (사용자에게 내부 정보를 노출하지 않는다)


데이터베이스 규약 샘플

## 데이터베이스 규약

### 테이블 설계
- 테이블명: snake_case, 복수형 (`users`, `order_items`)
- 컬럼명: snake_case
- 주키: `id` (UUIDv7)
- 타임스탬프: `created_at`, `updated_at`을 전 테이블에 부여
- 논리 삭제: `deleted_at` (NULL = 유효, 날짜시간 = 삭제됨)
- boolean 컬럼: `is_` 접두사 (`is_active`, `is_verified`)
- 개인정보 컬럼: 암호화 여부를 주석으로 명시 (`-- 암호화 저장`)

### 마이그레이션
- 마이그레이션 파일은 자동 생성된 것을 사용한다 (수동 편집 금지)
- 파괴적 변경 (컬럼 삭제, 타입 변경)은 새 마이그레이션으로 단계적으로 수행한다
- 프로덕션 적용 전 스테이징 환경에서 반드시 검증한다
- 시드 데이터는 `seed.ts`에 작성한다

### 쿼리 규칙
- N+1 쿼리 금지. 연관 데이터는 JOIN 또는 일괄 조회로 처리한다
- `SELECT *` 사용 금지. 필요한 컬럼만 명시한다
- 페이지네이션이 없는 전체 조회는 10,000건을 초과하지 않도록 경고 로그를 남긴다


국내 서비스 특화 규약 추가 예시

## 국내 서비스 특화 규약

### 전화번호 처리
- 전화번호는 하이픈 없는 11자리로 정규화하여 저장한다 (예: `01012345678`)
- 화면 표시 시에는 `lib/utils/formatPhone.ts`의 `formatPhone()` 함수를 사용한다
- 전화번호를 로그에 출력하지 않는다

### 금액 처리
- 금액은 항상 정수(원 단위)로 저장한다. 소수점 금액 금지
- 화면 표시 시에는 `lib/utils/formatPrice.ts`의 `formatPrice()` 함수를 사용한다
(예: `15000` → `"15,000원"`)
- 결제 금액 계산은 반드시 서버에서 수행한다. 클라이언트 계산 금지

### 날짜·시간
- DB 저장: UTC
- 화면 표시: KST (Asia/Seoul)로 변환
- `new Date()` 직접 사용 금지. `lib/utils/date.ts`의 헬퍼 함수를 사용한다
- 날짜 표시 형식: `yyyy.MM.dd` (예: `2025.03.20`)
- 시간 표시 형식: `HH:mm` (예: `14:30`)

### 에러 메시지
- 사용자에게 보이는 에러 메시지는 한국어로 작성한다
- 로그용 에러 메시지(서버)는 영어로 작성한다- 에러 메시지 문자열은 `constants/errorMessages.ts`에 상수로 정의한다



규약을 단계적으로 키우는 방법

CLAUDE.md의 규약은 처음부터 완벽하게 작성할 필요가 없습니다. 다음 사이클로 천천히 키워 나가세요.

1단계: 최소한의 규칙부터 시작한다

## 코딩 규약

- TypeScript strict 모드 사용
- 테스트는 반드시 작성한다
- any 타입 금지

이 3줄만 있어도 Claude Code의 출력에 눈에 띄는 변화가 생깁니다.


2단계: 불만이 생기면 그 자리에서 추가한다

Claude Code의 출력을 보고 "여기는 이렇게 해줬으면 했는데"라고 느낀 순간이 곧 규칙을 추가할 타이밍입니다. 나중에 몰아서 정리하려 하면 잊어버리기 쉽습니다.

예를 들어 Claude Code가 interface를 사용한 코드를 생성했는데 type을 원했다면, 즉시 추가합니다:

- 타입 정의에는 type을 사용한다. interface는 사용하지 않는다

3단계: 20~30개를 넘으면 정리한다

규칙이 쌓이다 보면 어느 순간 모순이 발생합니다. 규칙이 20~30개를 넘으면 전체를 검토하는 시간을 갖습니다.

카테고리별 그룹화: 타입, 명명, 함수, 임포트 등으로 분류

중복 제거: 같은 내용을 다른 표현으로 쓴 항목 정리

모순 해소: "A를 사용한다"와 "B를 사용한다"가 동시에 있는 경우 하나로 통일

불필요한 항목 삭제: 이미 린터·포매터가 자동으로 처리하는 항목 제거



©2024-2026 MDRules dev., Hand-crafted & made with Jaewoo Kim.

이메일문의: jaewoo@mdrules.dev


AI강의/개발/기술자문, AI 업무 자동화 컨설팅 문의: https://talk.naver.com/ct/w5umt5


AI 업무 자동화/에이전트/워크플로우설계 컨설팅/AI교육: https://mdrules.dev


이 작가의 멤버십 구독자 전용 콘텐츠입니다.
작가의 명시적 동의 없이 저작물을 공유, 게재 시 법적 제재를 받을 수 있습니다.

brunch membership
AI개발자작가님의 멤버십을 시작해 보세요!

AI Workflow Architect, LLM Engineer, Vibe Engineering, Claude Code, AI 업무 자동화 컨설팅/AI강의

86 구독자

오직 멤버십 구독자만 볼 수 있는,
이 작가의 특별 연재 콘텐츠

  • 최근 30일간 40개의 멤버십 콘텐츠 발행
  • 총 60개의 혜택 콘텐츠
최신 발행글 더보기
이전 03화CLAUDE.md 완전 정복 - 프로젝트 규모별 템플릿