네이밍, 레이어링, 에러 처리, 로깅 규칙을 강제하고 간단한 검사로 위반을 조기에 발견하는 Claude Code 스타일 가이드 프롬프트 작성법을 배우세요.

스타일 가이드 위반은 보통 한 번에 큰 실수로 나타나지 않습니다. 풀 리퀘스트에서 무해해 보이는 작은 "충분히 괜찮은" 선택들이 쌓여 코드베이스가 들쭉날쭉해지고 읽기 어려워질 때까지 점점 늘어납니다.
스타일 드리프트는 종종 이렇게 보입니다: 한 파일은 userID를 쓰고, 다른 파일은 userId, 또 다른 파일은 uid를 씁니다. 한 핸들러는 { error: "..." }를 반환하고, 다른 핸들러는 throw를 하고, 또 다른 핸들러는 로깅 후 null을 반환합니다. 각 변경은 작지만, 합쳐지면 규칙성이 사라진 레포가 됩니다.
빠른 반복과 여러 기여자가 더 문제를 악화시킵니다. 사람들은 특히 시간에 쫓길 때 보이는 것을 그대로 복사합니다. 레포에 가장 최근에 올라온 코드가 단축된 방식으로 작성됐다면, 그 방식이 다음 변경의 템플릿이 됩니다. 몇 주 후면 “기본 스타일”은 문서화된 가이드가 아니라 마지막으로 일어난 일입니다.
그래서 목표는 개인 취향이 아니라 일관된 규칙이어야 합니다. 질문은 "내가 이 이름을 좋아하는가?"가 아니라 "다음 사람이 별 생각 없이 따라갈 수 있도록 우리가 합의한 규칙에 맞는가?"입니다.
위반을 초기에 잡는다는 건 잘못된 패턴이 복사-붙여넣기 연료가 되기 전에 차단하는 것을 의미합니다. 새로 추가되거나 수정된 코드에 집중하고, 새로운 불일치의 첫 등장을 고쳐서 새로운 드리프트를 도입하는 머지를 차단하세요. 문제를 지적할 때는 사람들이 다음 번에 그대로 따라할 수 있는 짧은 예시를 덧붙이세요.
현실적인 예: 개발자가 새 API 엔드포인트를 추가하면서 디버깅용으로 원시 요청 바디를 로깅합니다. 이 변경이 병합되면 다음 엔드포인트도 복사하고, 곧 민감한 데이터가 로그에 찍히게 됩니다. 첫 PR에서 잡으면 비용이 적습니다. 퍼진 뒤에 잡으면 고통스럽고 위험합니다.
스타일 가이드는 리뷰에서 체크리스트처럼 읽힐 때만 작동합니다. 각 지침을 diff에서 검사할 수 있는 규칙으로 다시 써야 합니다.
규칙을 네 가지 버킷으로 정리하세요: 네이밍, 레이어링, 에러 처리, 로깅. 각 버킷마다 두 가지를 작성하세요: 반드시 지켜야 할 것과 금지된 것.
각 규칙의 강도를 미리 정하세요:
리뷰가 끝없는 리팩터링이 되지 않도록 범위를 정하세요. 간단한 규칙이 잘 작동합니다: "새로 추가되거나 수정된 코드만 준수해야 한다; 기존에 손대지 않은 코드는 수리로 재작성하지 않는다." 정리 작업이 필요하다면 별도 작업으로 시간 상한을 두세요.
또한 리뷰에서 원하는 출력물을 정의하세요: 통과/실패 판단, 파일과 줄 참조가 있는 위반 목록, 구체적인 편집으로 제시된 수정 제안, 버그나 유출을 초래할 수 있는 경우의 간단한 위험 설명.
예: PR이 원시 사용자 토큰을 로그에 남기면 "로깅: 비밀 정보 절대 로깅 금지" 아래에서 리뷰가 실패해야 하고 대신 요청 ID를 로깅하라는 제안을 해야 합니다.
스타일 프롬프트는 취향처럼 들리면 실패합니다. 좋은 리뷰 프롬프트는 계약처럼 읽혀야 합니다: 명확한 비협상 항목, 명확히 이름 붙은 예외, 예측 가능한 출력.
두 개의 짧은 블록으로 시작하세요: 반드시 참이어야 할 것과 유연하게 적용해도 되는 것. 그다음 결정 규칙을 추가하세요: "불분명하면 Needs Clarification로 표시하라. 추측하지 말라."
증거를 강제하세요. 도구가 위반을 표시하면 모호한 설명 대신 정확한 식별자와 파일 경로를 인용하도록 요구하세요. 이 한 가지 제약이 많은 왕복을 줄여줍니다.
범위를 좁게 유지하세요: 변경된 라인과 직접 영향을 받는 코드 경로만 코멘트하세요. 관련 없는 리팩터를 허용하면 스타일 강제는 "파일을 다시 써라"로 변하고, 사람들은 피드백을 신뢰하지 않게 됩니다.
재사용 가능한 구조 예시는 다음과 같습니다:
Role: strict style guide reviewer.
Input: diff (or files changed) + style guide rules.
Non-negotiables: [list].
Allowed exceptions: [list].
Scope: ONLY comment on changed lines and directly impacted code paths. No unrelated refactors.
Evidence: Every finding MUST include (a) file path, (b) exact identifier(s), (c) short quote.
Output: structured compliance report with pass/fail per category + minimal fixes.
리포트는 매번 같은 섹션을 유지하도록 요구하세요. 섹션이 비어도 "문제 없음"으로 표기해야 합니다: Naming, Layering, Error handling, Logging.
예: "서비스 레이어가 DB 세부사항을 노출한다"고 판단하면 internal/orders/service/order_service.go와 정확한 호출(예: db.QueryContext)을 인용해야 논쟁 없이 누수를 바로 고칠 수 있습니다.
스타일 가이드는 프로세스가 반복 가능할 때 정착합니다. 목표는 모델이 취향을 논쟁하지 않고 규칙을 검사하게 만드는 것입니다.
간단한 2단계 워크플로우를 사용하세요:
예: PR이 새 엔드포인트를 추가하면 1차는 핸들러가 PostgreSQL에 직접 접근(레이어링), 요청 구조체의 혼합된 네이밍(네이밍), 전체 이메일을 로깅(로깅)을 지적합니다. 2차는 최소 변경으로 DB 호출을 서비스 또는 리포지토리로 옮기고, 구조체 이름을 통일하고, 로그에서 이메일을 마스킹합니다. 그 외는 바꾸지 않습니다.
네이밍 문제는 사소해 보이지만 실제 비용을 만듭니다: 사람이 의도를 오해하고, 검색이 어려워지고, 거의 같은 이름이 늘어납니다.
리뷰어가 변경 전체에서 강제해야 할 네이밍 규칙을 명시하세요: 파일명, 내보내진 타입, 함수, 변수, 상수, 테스트까지. 케이스(camelCase, PascalCase, snake_case)를 분명히 하고 약어 규칙 하나를 선택하세요(예: APIClient vs ApiClient). 그리고 변경 전반에 걸쳐 적용하세요.
공유 어휘도 표준화하세요: 에러 타입, 로그 필드, 설정 키. 로그에서 request_id를 쓰면 한 파일에서 reqId나 requestId를 허용하지 마세요.
실용적인 리뷰어 지시는 다음과 같습니다:
Check every new or renamed identifier. Enforce casing + acronym rules.
Flag vague names (data, info, handler), near-duplicates (userId vs userID), and names that contradict behavior.
Prefer domain language: business terms over generic tech words.
짧은 보고서를 요청하세요: 가장 혼란스러운 이름 세 가지, 근접 중복과 어느 것을 유지할지, 표준과 맞지 않는 로그/설정/에러 이름.
레이어링 규칙은 평범한 언어로 말할 때 가장 잘 작동합니다: 핸들러는 HTTP를 다루고, 서비스는 비즈니스 규칙을 담당하며, 리포지토리는 DB와 통신합니다.
의존 방향을 고정하세요. 핸들러는 서비스만 호출할 수 있습니다. 서비스는 리포지토리만 호출할 수 있습니다. 리포지토리가 서비스나 핸들러를 호출해서는 안 됩니다. 핸들러는 데이터베이스 코드, SQL 헬퍼, ORM 모델을 직접 임포트하면 안 됩니다. 공용 패키지(config, time, IDs)는 앱 로직이 없어야 합니다.
횡단 관심사를 한 장소로 고정하세요. 요청 형태 검증은 경계에서, 비즈니스 규칙 검증은 서비스에서 하는 것이 보통입니다. 권한 부여는 보통 핸들러에서 시작(신원, 스코프)하지만 최종 결정은 서비스가 강제해야 합니다. 매핑(mapping)은 레이어 경계에서 수행하세요: 핸들러는 HTTP를 도메인 입력으로, 리포지토리는 DB 행을 도메인 타입으로 매핑합니다.
프롬프트에 다음을 넣어 리뷰를 구체적으로 유지하세요:
Check layering: handler -> service -> repository only.
Report any leaks:
- DB types/queries in handlers or services
- HTTP request/response types inside services or repositories
- repository returning DB models instead of domain objects
- auth/validation mixed into repository
For each leak, propose the smallest fix: move function, add interface, or rename package.
리포트를 명확히 만드세요: 파일명, 속해야 할 레이어, 규칙을 깨는 임포트나 호출, 그리고 패턴 확산을 막기 위한 최소 변경.
대부분의 스타일 논쟁은 프로덕션에서 문제가 생길 때 커집니다. 명확한 에러 처리 정책은 모두가 "올바른" 것이 무엇인지 알게 해 수정을 차분하게 만듭니다.
철학을 쓰고 그것을 강제하세요. 예: "문맥을 추가하기 위해 에러를 래핑하라; 의미를 바꾸거나 사용자 메시지로 매핑할 때만 새로운 에러를 생성하라. 시스템 경계에서는 원시 에러를 그대로 반환하지 말라." 이 한 문장이 임의 패턴의 확산을 막습니다.
사용자에게 보여줄 텍스트와 내부 세부를 분리하세요. 사용자 메시지는 짧고 안전해야 합니다. 내부 에러는 작업명과 핵심 식별자를 포함할 수 있지만 비밀은 포함하면 안 됩니다.
리뷰에서는 몇 가지 반복되는 실패를 확인하세요: 에러를 삼켜버림(로그는 했으나 반환하지 않음), 모호한 반환(실패 후 nil 값과 nil 에러), 스택 트레이스나 쿼리 텍스트, 토큰, PII가 유출되는 사용자 메시지. 리트라이나 타임아웃을 지원하면 명시적으로 요구하세요.
예: 체크아웃 호출이 타임아웃되면 사용자는 "결제 서비스가 너무 오래 걸립니다."를 보게 됩니다. 내부적으로는 타임아웃을 래핑하고 op=checkout.charge와 주문 ID를 포함해 검색 가능하고 조치 가능한 형태로 만드세요.
로그는 모두가 동일한 방식으로 작성할 때만 도움이 됩니다. 각 개발자가 문구, 레벨, 필드를 제각각 고르면 검색은 추측 작업이 됩니다.
로그 레벨은 비협상 항목으로 만드세요: debug는 개발 상세, info는 정상 마일스톤, warn은 예측하지 못했지만 처리된 상황, error는 사용자 행동이 실패하거나 주의가 필요한 경우. "fatal"이나 "panic"은 드물게 사용하고 명확한 크래시 정책과 연결하세요.
구조화된 로그는 완벽한 문장보다 중요합니다. 대시보드와 알림이 깨지지 않도록 안정적인 키 이름을 요구하세요. 핵심 필드 집합(예: event, component, action, status, duration_ms)을 작게 정하고 일관되게 유지하세요.
민감한 데이터는 절대 로깅하면 안 됩니다. 로깅 금지 항목을 명시하세요: 비밀번호, 인증 토큰, 전체 신용카드 정보, 비밀, 원시 개인 데이터. 겉보기엔 무해해 보이지만 위험한 것들(비밀번호 재설정 링크, 세션 ID, 전체 요청 바디)도 지목하세요.
상관 ID(correlation ID)는 레이어 전반의 디버깅을 가능하게 합니다. 요청 내 모든 로그 라인에 request_id가 있어야 한다고 요구하세요. user_id를 로깅할 때 언제 허용되는지와 익명 사용자일 경우 어떻게 표현할지도 정의하세요.
재사용 가능한 프롬프트 블록 예시는 다음과 같습니다:
Review the changes for logging conventions:
- Check level usage (debug/info/warn/error). Flag any level that does not match impact.
- Verify structured fields: require stable keys and avoid free-form context in the message.
- Confirm correlation identifiers: request_id on all request-bound logs; user_id only when allowed.
- Flag any sensitive data risk (tokens, secrets, personal data, request/response bodies).
- Identify noisy logs (in loops, per-item logs, repeated success messages) and missing context.
Return: (1) violations with file/line, (2) suggested rewrite examples, (3) what to add or remove.
병합 전에 빠른 "안전 점검"을 하세요: 요청 관련 작업의 모든 새 로그에 request_id가 빠져있는지, 기존 이름을 바꾸는 새 키가 있는지(userId vs user_id), 실패한 작업이 무엇인지(작업, 리소스, 상태)를 빠르게 파악할 수 없는 에러 로그가 있는지, 모든 요청에서 실행되는 고빈도 로그가 있는지, 필드나 메시지에 비밀이나 개인 데이터가 노출될 가능성이 있는지 확인합니다.
스타일 드리프트를 제안이 아닌 빌드 실패처럼 취급하세요. 병합 전에 실행되는 엄격한 게이트를 추가하고 명확한 통과 또는 실패를 반환하게 하세요. 필수 규칙(네이밍, 레이어 경계, 로깅 안전, 에러 처리)이 깨지면 실패하고 정확한 파일과 줄을 가리켜야 합니다.
게이트를 짧게 유지하세요. 실용적인 트릭 중 하나는 규칙별 YES/NO 체크리스트를 요구하고 하나라도 NO면 승인을 거부하는 것입니다.
대부분 문제를 잡는 PR 사이즈 체크리스트 예시는 다음과 같습니다:
도구가 수정을 제안하면, 건드린 규칙마다 작은 준수 스니펫을 요구하세요. 이렇게 하면 "명확하게 바꿔라" 같은 모호한 피드백을 막을 수 있습니다.
스타일 가이드가 실패하는 가장 빠른 방법은 해석의 여지를 남기는 것입니다. 동일한 규칙을 두 명의 리뷰어가 읽고 서로 다른 결론을 내릴 수 있다면, 도구는 기준이 아닌 취향을 강제하게 됩니다.
네이밍이 흔한 예입니다. "명확한 이름을 사용하라"는 검사 불가능합니다. 이를 검증 가능한 문장으로 좁히세요: "함수는 동사로 시작(예: createInvoice), 불리언은 is/has/can으로 시작, 내보낸 타입은 PascalCase."
또 다른 함정은 한 번에 모든 것을 요구하는 것입니다. 하나의 프롬프트가 네이밍, 레이어링, 에러, 로깅, 테스트, 성능을 모두 다루려 하면 피드백이 얕아집니다. 깊이가 필요하면 리뷰를 분리하거나 게이트 프롬프트를 필수 규칙으로 제한하세요.
집행이 흔들리게 만드는 문제들:
프롬프트를 테스트처럼 취급하면 예측 가능한 강제력이 생깁니다. 조언처럼 취급하면 위반이 숨어들어 증식합니다.
디프(레포 전체가 아니라)를 빠르게 확인하고 다음을 확증하세요:
작은 프롬프트 템플릿을 유지하고 변경마다 붙여넣으세요:
Review ONLY the changed code against our rules for naming, layering, errors, and logging.
List mandatory violations first (with file + line if available). Then list optional suggestions.
End with either: “no mandatory violations found” or “mandatory violations found”.
예: 핸들러에 procUsr()라는 새 함수가 있고 그 함수가 PostgreSQL을 직접 쓰는 경우, 기능이 동작하더라도 네이밍과 레이어링에서 실패해야 합니다. 여기서 잡으면 복사-붙여넣기로 실수가 확산되는 것을 막을 수 있습니다.
동료가 새 엔드포인트 POST /v1/invoices/{id}/send를 추가하고 핸들러, 서비스, 스토리지를 건드립니다.
첫 번째 패스에서는 리포트만 원합니다. 재작성은 원치 않습니다:
Pass 1 (report only)
You are a strict style checker. Read the patch.
Rules: naming must match our guide, handlers call services only, services call storage only, no SQL in handlers,
errors must be wrapped with context, logs must be structured and not leak PII.
Output: a numbered list of violations with file:line, rule name, and one-sentence impact. Do not propose fixes.
If a rule might be intentionally broken, ask one clarification question.
전형적인 발견 항목: SendInvoiceNow() vs SendInvoice 네이밍 불일치, 핸들러가 db.QueryRow를 직접 호출, 문맥 없는 err 반환, 그리고 log.Printf("sending invoice %v", invoice)처럼 전체 객체를 덤프하는 시끄러운 로그.
두 번째 패스는 최소한의 안전한 변경을 요청합니다:
Pass 2 (minimal fix suggestions)
Using the violations list, propose the smallest code edits to comply.
Constraints: keep behavior the same, no refactors beyond what is needed, show suggested function names and where code should move.
For each fix, include 1-2 lines of example code.
규칙 위반이 허용되는 경우에는 미리 말하게 하세요: "예외는 허용되지만 그 이유를 짧게 주석으로 달고 예외를 제거할 후속 작업을 추가해야 합니다."
수정 후 핸들러는 얇은 어댑터가 되고 서비스가 워크플로를 소유하며 스토리지가 쿼리를 소유합니다. 에러는 fmt.Errorf("send invoice: %w", err)처럼 래핑되고 로그는 안전한 필드(전체 인보이스가 아니라 인보이스 ID)만 포함한 한 줄로 바뀝니다.
팀에서 승인한 하나의 프롬프트를 골라 공유 도구처럼 사용하세요. 리뷰에서 자주 문제를 일으키는 항목(네이밍 드리프트, 레이어 누수, 일관성 없는 에러, 안전하지 않은 로그)부터 시작하세요. 실제 코드에서 진짜 위반이 발견될 때만 프롬프트를 업데이트하세요.
프롬프트 상단에 작은 규칙 블록을 두고 매 리뷰 동일하게 붙여넣으세요. 모두가 매번 규칙을 편집하면 표준이 아니라 논쟁이 됩니다.
간단한 주기 규칙을 만드세요: 한 사람이 한 주 동안 가장 많이 발생한 스타일 실수를 모아 정확히 한 가지 규칙을 추가하거나 더 나은 예시 하나를 추가합니다.
채팅 기반 빌드 흐름(예: Koder.ai (koder.ai))에서 작업한다면 변경 중에도 동일한 게이트 체크를 실행할 가치가 있습니다. 계획, 스냅샷, 롤백 같은 기능은 스타일 수정을 작고 되돌리기 쉽게 만들어 소스 코드를 내보내기 전까지 관리하기 좋습니다.