AI & Tools

바이브 코딩(Vibe Coding) 사고, 룰 파일로 애초에 막는 법

바이브 코딩 사고는 코드를 읽는 단계가 아니라 첫 룰 파일을 쓰는 단계에서 갈립니다. CLAUDE.md·.cursorrules에 담을 보안·중복·아키텍처·완료 기준·스코프 다섯 규칙을 예시 문장까지 정리했습니다.

이석우iOS Developer11분 읽기
바이브 코딩(Vibe Coding) 사고, 룰 파일로 애초에 막는 법 대표 이미지

지난 글에서 바이브 코딩의 대가, 그러니까 코드를 안 읽고 개발하면 생기는 문제 세 가지를 정리했습니다.

버그를 못 고치게 되고, 같은 기능이 여러 군데 생기고, 조용한 보안 구멍이 뚫린다는 얘기였죠. 그리고 해결책으로 “치명적인 곳만 읽기”, “AI 요약 읽기”, “스캐너 걸기”를 제안했습니다.

그런데 이 해결책들에는 공통점이 하나 있습니다. 전부 사고가 난 다음에 잡아내는 사후 검증이라는 점이에요.

이번 글은 한 걸음 더 들어갑니다. 검증 이전에, 애초에 AI가 그런 코드를 못 만들게 강제하는 방법입니다.

도구는 이미 다들 갖고 있어요. CLAUDE.md, .cursorrules, AGENTS.md 같은 룰 파일입니다.

바이브 코딩의 승부는 코드를 읽는 단계가 아니라, 첫 룰 파일을 쓰는 단계에서 갈립니다.

RULES FIRST 텍스트와 코드 골조 청사진 앞을 막아선 규칙집 썸네일
바이브 코딩 2편, 코드보다 룰 파일이 먼저입니다

왜 룰 파일인가 — AI는 매번 처음 입사한 신입입니다

AI 코딩 도구의 근본 특성부터 짚고 갈게요. AI는 세션이 끝나면 대부분을 잊습니다.

어제 “API 키는 환경 변수로 빼라”고 말했어도, 오늘 새 세션에서는 그 대화가 없던 일이 돼요.

그래서 매 세션 반복되는 지시는 대화가 아니라 파일로 박아야 합니다.

CLAUDE.md(Claude Code), .cursorrules(Cursor), AGENTS.md(Codex 등 범용)가 그 예입니다. 이런 룰 파일은 세션이 시작될 때마다 자동으로 프롬프트에 올라갑니다.

사람으로 치면 매일 아침 출근하는 신입에게 쥐여주는 온보딩 문서인 셈이죠.

이게 왜 바이브 코딩과 특히 궁합이 좋냐면, 바이브 코딩은 정의상 사람이 코드를 안 읽는 방식이기 때문입니다.

사람 검토가 빠진 자리를 뭔가가 대신 채워야 하는데, 그 첫 번째 후보가 “생성 시점의 규칙”이에요. 나쁜 코드를 걸러내는 것보다 나쁜 코드가 안 나오게 하는 쪽이 훨씬 쌉니다.

전편의 문제 세 가지에, 코드를 안 읽으면 잡아낼 수 없는 AI 특유의 사고 두 가지를 더해 총 다섯 가지를 룰로 어떻게 막는지 보겠습니다.


룰 1. 보안 — “하지 마라”가 아니라 “이렇게 해라”까지 쓰기

전편에서 본 API 키 하드코딩부터 잡아볼게요. 룰 파일에 이렇게 씁니다.

## 보안 규칙 (위반 시 코드 생성 중단하고 보고할 것)

- API 키·토큰·비밀번호를 코드에 하드코딩하지 않는다.
  반드시 환경 변수(.env) 또는 시크릿 매니저에서 읽는다.
- .env 파일은 절대 커밋하지 않는다. .env.example만 커밋한다.
- 사용자 입력은 신뢰하지 않는다. SQL은 파라미터 바인딩,
  HTML 출력은 이스케이프를 기본으로 한다.
- 파일 삭제·DB 마이그레이션·외부 결제 API 호출 코드를 짤 때는
  실행 전에 반드시 사용자에게 확인을 받는다.
- 새 라이브러리는 무단으로 설치하지 않는다. 패키지 이름과
  선택 이유를 먼저 제안하고, 승인 후에 추가한다.

여기서 포인트가 두 가지 있습니다.

첫째, 금지만 쓰지 말고 대안을 같이 쓰세요. “하드코딩 금지”만 있으면 AI가 우회로를 알아서 찾아야 합니다.

“환경 변수에서 읽어라”까지 쓰면 고민 없이 그 길로 갑니다. 규칙의 준수율은 대안의 구체성에 비례합니다.

둘째, 위험 등급이 다른 작업은 절차 자체를 다르게 하세요. 삭제·결제·마이그레이션은 “확인 후 진행”으로 못 박으면, Accept All을 누르는 흐름 속에서도 그 지점에서만큼은 브레이크가 걸립니다.

마지막 줄의 의존성 규칙도 보안의 연장선입니다. AI가 추천하는 패키지 이름 중 5~21%는 레지스트리에 실제로 존재하지 않는다는 조사가 있는데, 무서운 건 그다음이에요.

공격자들이 AI가 자주 지어내는 가짜 이름을 미리 선점해 악성 패키지를 올려둡니다. 슬롭스쿼팅(slopsquatting) 공격이 실제로 벌어지고 있는 겁니다.

설치 명령까지 Accept All로 넘기는 바이브 코딩에서는 이 경로가 그대로 공급망 사고로 이어집니다. 그래서 “새 패키지는 제안 후 승인”을 절차로 박아두는 게 안전합니다.


룰 2. 중복 — “만들기 전에 찾아라”를 명문화하기

같은 기능이 여러 군데 생기는 문제의 원인은 AI가 게을러서가 아닙니다. AI는 컨텍스트에 안 보이는 코드는 없는 코드로 취급하기 때문이에요.

프로젝트가 커질수록 전체 코드가 컨텍스트에 안 들어가니, 비슷한 함수를 새로 만드는 게 AI 입장에선 합리적 선택이 됩니다.

그래서 룰로 탐색을 강제합니다.

## 중복 방지 규칙

- 새 함수·컴포넌트를 만들기 전에 반드시 기존 코드베이스를
  검색해서 같은 역할이 이미 있는지 확인한다.
- 날짜 처리는 src/utils/date.ts, API 호출은 src/lib/api.ts에
  이미 있는 함수를 쓴다. 없으면 그 파일에 추가한다.
- 두 곳 이상에서 쓰이는 로직은 즉시 공용 모듈로 추출한다.
- 기존 함수와 거의 같은 함수가 필요해 보이면, 새로 만들지 말고
  기존 함수를 확장할 수 있는지 먼저 검토해 사용자에게 제안한다.

두 번째 줄이 특히 효과가 큽니다. “중복 만들지 마라”는 추상적 규칙보다 “날짜 처리는 이 파일에 있다”는 지도가 훨씬 잘 먹혀요.

AI가 검색을 건너뛰더라도 룰 파일에 적힌 경로는 항상 눈앞에 있으니까요. 프로젝트의 공용 모듈 위치를 룰 파일에 목록으로 유지하는 것만으로 중복 생성이 눈에 띄게 줄어듭니다.

로봇 배달부를 기존 공용 모듈 건물로 안내하는 코드베이스 도시 지도
공용 모듈의 위치를 알려주면 AI는 중복 건물을 짓지 않습니다

룰 3. 아키텍처 — 폴더 구조와 의존 방향을 헌법으로 만들기

셋 중 가장 조용히 무너지는 게 아키텍처입니다. 보안 사고는 터지면 알고 중복은 검색하면 보이는데, 아키텍처는 어느 날 돌아보면 이미 스파게티가 돼 있어요.

AI는 “지금 이 요청을 가장 빨리 해결하는 코드”를 짜는 경향이 있습니다. 그래서 레이어를 건너뛰는 지름길을 아무렇지 않게 뚫어요.

뷰에서 DB를 직접 부르는 식으로요.

이것도 룰로 막을 수 있습니다. 핵심은 구조와 의존 방향을 명시하는 겁니다.

## 아키텍처 규칙

프로젝트 구조:
- src/views/     : UI. 상태와 이벤트만 다룬다
- src/services/  : 비즈니스 로직
- src/repositories/ : 데이터 접근. DB·API 호출은 여기서만

의존 방향은 views → services → repositories 단방향.
- views에서 repositories를 직접 import하지 않는다
- repositories에서 views를 import하지 않는다
- 새 기능도 반드시 이 3계층 구조를 따른다.
  구조를 벗어나야 할 이유가 있으면 코드를 짜기 전에 사용자에게 설명한다

이 룰의 진짜 가치는 첫 뼈대가 잡힌 뒤에 나타납니다.

AI는 기존 코드의 패턴을 강하게 따라 하는 성질이 있습니다. 초반 코드가 3계층을 지키고 있으면 이후 코드도 자연스럽게 그 결을 타요.

반대로 초반에 지름길이 하나라도 뚫려 있으면 AI는 그걸 “이 프로젝트의 허용된 패턴”으로 학습합니다.

그래서 이 글의 부제가 “처음 뼈대”입니다.

프로젝트 생성 직후, 코드가 10줄일 때 룰 파일과 폴더 구조를 먼저 잡는 것. 이게 나중에 1만 줄에서 리팩터링하는 것보다 수백 배 쌉니다.


룰 4. 완료 기준 — “된 것 같다”와 “됐다”를 구분하기

여기서부터는 전편에서 다루지 않은, AI 코딩 특유의 사고 유형입니다.

AI는 코드를 다 짜면 확인 없이 “완료했습니다”라고 말하는 습성이 있습니다. 실제로는 컴파일조차 안 되는 코드인데도요.

사람이 diff를 읽는 워크플로에서는 금방 들통나지만, 바이브 코딩에서는 “완료”라는 말만 믿고 다음 요청으로 넘어가게 됩니다. 그래서 완료의 정의 자체를 룰로 박아야 합니다.

## 완료 기준 규칙

- 작업 완료를 선언하기 전에 반드시 typecheck·lint·테스트를
  실행하고, 그 결과를 함께 보고한다
- 테스트가 실패하면 코드를 고친다. 테스트를 수정·삭제해서
  통과시키지 않는다. 테스트 자체가 잘못됐다고 판단되면
  고치지 말고 먼저 보고한다
- 에러를 try/catch로 감싸서 조용히 삼키지 않는다.
  잡은 에러는 반드시 로그를 남기거나 위로 전달한다

두 번째 규칙이 핵심입니다. AI에게 “테스트를 통과시켜라”가 목표로 주어지면, 코드를 고치는 대신 실패하는 테스트 쪽을 고쳐버리는 일이 실제로 일어납니다.

목표 달성의 최단 경로를 찾은 거죠. 코드를 안 읽는 사람 입장에서는 검증 장치가 무력화된 줄도 모르고 초록불만 보게 됩니다.

세 번째 규칙은 전편의 문제 1번(버그를 못 고치게 된다)과 직결됩니다.

AI는 방어적으로 짠다며 에러를 삼키는 try/catch를 둘러두는 경향이 있는데, 이러면 문제가 생겨도 화면은 멀쩡해 보여요. 나중에 정말 필요한 에러 메시지가 어디에도 남지 않아 디버깅이 한층 더 막막해집니다.


룰 5. 스코프 — 시킨 것만 하게 하기

AI 코딩의 또 다른 대표 사고는 시키지 않은 일까지 하는 것, 이른바 스코프 크립(scope creep)입니다. 버튼 색을 바꿔달라고 했는데 “겸사겸사” 주변 코드를 리팩터링하고, 헬퍼 함수를 새로 뽑고, 파일 구조까지 바꿔놓는 식이죠.

선의처럼 보이지만 바이브 코딩에서는 치명적입니다. diff를 안 읽으니 요청한 적 없는 변경이 섞여 들어와도 모르고 나중에 뭔가 깨졌을 때 원인 후보가 몇 배로 늘어나거든요.

## 스코프 규칙

- 요청받은 작업만 한다. 작업 중 발견한 개선점은 코드를
  고치지 말고, 작업 완료 후 목록으로 제안한다
- 요청과 무관한 파일은 수정하지 않는다
- 리팩터링은 별도로 요청받았을 때만 한다

효과는 수치로도 확인됩니다. 룰 파일에 스코프 규칙 몇 줄을 추가하는 것만으로, 되돌리기(revert)와 범위 이탈 비율이 41%에서 12%로 떨어졌다고 합니다.

30일 실측 보고에 나온 수치예요. 룰 다섯 종류 중 투자 대비 효과가 가장 큰 축입니다.


룰만으로는 안 됩니다 — 이중 잠금 걸기

여기까지 읽고 “그럼 룰만 잘 쓰면 코드 안 읽어도 되겠네”라고 생각할 수 있는데, 함정이 하나 있습니다. 룰은 확률을 높이는 장치지 보장이 아니에요.

AI는 컨텍스트가 길어지면 룰을 잊기도 하고 급하면(정확히는 그렇게 보이는 상황이면) 지름길을 택하기도 합니다.

그래서 중요한 룰일수록 기계 검증과 짝을 지어야 합니다. 룰이 1차 잠금, 도구가 2차 잠금입니다.

룰 (생성 시점 예방) 도구 (커밋·CI 시점 검증)
시크릿 하드코딩 금지 gitleaks pre-commit 훅
중복 로직 금지 jscpd 같은 중복 탐지기
레이어 의존 방향 강제 dependency-cruiser, eslint-plugin-boundaries
완료 기준(테스트·타입체크) CI 파이프라인 게이트
테스트 파일 무단 수정 금지 CODEOWNERS로 테스트 폴더 보호
코드 스타일 ESLint·Prettier·SwiftLint

이 조합의 힘은 되먹임에 있습니다. 도구가 룰 위반을 잡으면 그 에러 메시지가 다시 AI에게 들어가고, AI는 룰 파일을 다시 참조해서 고칩니다.

사람이 개입하지 않아도 예방 → 검증 → 수정 루프가 돌아가는 거예요. 전편에서 말한 “사람이 안 읽을 거면 기계라도 읽게 하라”가 룰과 만나면 완성됩니다.

린트 규칙으로 강제할 수 있는 건 린트로 옮기세요. 룰 파일에는 도구로 못 잡는 것(확인 절차, 설계 의도, 프로젝트 맥락)을 남기는 게 이상적인 분업입니다.

RULES와 CI 두 자물쇠로 잠긴 금고문과 예방·검증·수정 순환 화살표
룰이 1차 잠금, 도구가 2차 잠금 — 예방·검증·수정 루프

실전: 프로젝트 시작 10분 체크리스트

새 프로젝트에서 바이브 코딩을 시작하기 전, 첫 프롬프트를 치기 전에 이것부터 하세요.

  1. 룰 파일 생성 — 보안·중복·아키텍처·완료 기준·스코프 다섯 섹션. 위 예시를 복사해서 프로젝트에 맞게 고치면 10분이면 됩니다
  2. 폴더 뼈대 먼저 커밋 — 빈 폴더라도 구조를 먼저 만들어두면 AI가 그 결을 따릅니다
  3. 시크릿 스캐너 훅 설치 — gitleaks 하나면 최악의 사고는 막습니다
  4. .env.example 생성 — “키는 여기에”라는 신호를 코드베이스 차원에서 주는 겁니다

그리고 운영하면서 한 가지만 기억하면 됩니다. AI가 같은 실수를 두 번 하면, 그건 AI 탓이 아니라 룰 파일에 그 규칙이 없다는 신호입니다.

사고가 날 때마다 룰을 한 줄씩 보강하세요. 룰 파일은 한 번 쓰고 끝나는 문서가 아니라, 프로젝트와 함께 자라는 문서입니다.

Q. 룰 파일이 길어지면 오히려 안 지킨다던데요?

A. 맞습니다. 룰도 컨텍스트를 차지해서, 길수록 개별 규칙의 무게가 희석됩니다.

“항상 지켜야 하는가?“를 기준으로 슬림하게 유지하고, 도구로 잡을 수 있는 건 도구로 넘기세요. 경험상 한 화면(100줄 안팎)을 넘기 시작하면 다이어트가 필요합니다.

Q. 이미 스파게티가 된 프로젝트에도 소용 있나요?

A. 있습니다. 다만 순서가 달라요.

먼저 AI에게 현재 구조를 분석시켜 룰 파일 초안을 뽑습니다. 그다음 “새 코드부터는 이 규칙을 따르되 기존 코드는 건드리는 김에 고친다”는 점진 전략을 룰에 명시하는 방식이 현실적입니다.

Q. CLAUDE.md, .cursorrules, AGENTS.md 다 따로 관리해야 하나요?

A. 내용은 하나로 쓰고 파일만 복제하는 게 보통입니다.

최근에는 AGENTS.md를 표준처럼 두고 다른 파일이 이를 참조하게 하는 흐름도 있습니다. 도구를 여럿 쓴다면 AGENTS.md를 원본으로 삼는 걸 권합니다.


정리하겠습니다. 전편의 결론이 “속도는 AI에게, 판단은 나에게”였다면 이번 편의 결론은 이겁니다.

판단을 매번 하지 말고, 한 번 내린 판단을 룰로 박아두세요.

코드를 읽는 건 사고를 발견하는 일이고, 룰을 쓰는 건 사고를 예방하는 일입니다. 바이브 코딩으로 속도를 챙기면서도 무너지지 않는 프로젝트의 공통점은 화려한 프롬프트가 아니라 잘 자란 룰 파일이었습니다.

오늘 진행 중인 프로젝트에 룰 파일이 없다면, 다음 기능을 시키기 전에 위의 다섯 섹션부터 만들어보세요.

룰 파일과 메모리 기능의 차이, 그리고 어떤 내용을 어디에 둬야 하는지는 별도 글에서 자세히 다뤘으니 함께 보시면 좋습니다.

참고 자료

이어서 읽기