콘텐츠로 이동

루프를 닫다 — TDD·Codex 리뷰·hook·ratchet

하네스의 절반은 “행동 전 규칙(가이드)“이고, 나머지 절반은 “행동 후 검증(센서)“입니다. 이 글은 그 검증 — 즉 피드백 루프를 어떻게 닫았는가에 관한 것입니다. 규칙은 멋진 말이 아니라, 검증이 받쳐줄 때만 비로소 규칙이 됩니다. 검증이 없으면 규칙은 그냥 잊혀진 메모일 뿐입니다.

“테스트를 먼저 써라”, “파일을 작게 유지하라”, “이미 있는 걸 또 만들지 마라” — 이런 규칙을 문서에 적어두기만 하면 어떻게 될까요? AI는 잊거나 건너뜁니다. 사람도 그렇습니다. 마감이 급하거나, 맥락이 길어지거나, 단순히 잊어서요. 규칙을 문서로만 두는 건 “운전 조심하세요”라고 적은 표지판과 같습니다. 아무도 그 표지판 때문에 속도를 줄이지 않습니다.

그래서 규칙마다 그것이 지켜졌는지 기계가 자동으로 확인하고, 안 지켜졌으면 작업을 막는 루프를 붙였습니다. 과속 카메라처럼요. 표지판(규칙)과 카메라(검증)가 함께 있을 때만 속도가 줄어듭니다. 이 루프를 네 겹으로 깔았습니다.

루프가 닫혀야 규칙이 산다 ① 행동 (코드 작성) ② 자동 검사테스트·린트·리뷰 ✓ 통과 → 진행 ✗ 차단 → 되돌림 차단되면 다시 ①로 — 사람 손 없이 고리가 닫힌다
닫힌 피드백 루프(개념도). 행동 후 자동 검사가 통과/차단을 판정하고, 차단되면 다시 행동으로 돌아갑니다. 이 고리가 닫혀야 규칙이 사람 손 없이도 유지됩니다.

우리 프로젝트의 첫 번째 철칙은 이것입니다.

테스트 전에 쓴 코드는 삭제한다. 실패하는 테스트(RED)를 본 적이 없으면 그 구현은 무효다.

이걸 말로만 두지 않았습니다. 핵심 소스 파일(서비스·모델·API·훅 등)을 작성할 때 최근에 테스트를 손댄 흔적이 없으면 작업이 막히도록 커밋 훅에 걸었습니다. “테스트 먼저”가 권고가 아니라 통과 조건이 된 것입니다.

TDD의 보너스도 컸습니다. 테스트는 나중에 거대 파일을 분할할 때 “동작이 안 바뀌었다”는 유일한 증거가 됐습니다. 분할 전과 후에 같은 테스트가 GREEN이면, 내부를 아무리 갈라도 바깥 동작은 그대로라는 뜻입니다. 테스트가 없으면 god 파일 분할은 눈 감고 수술하는 것과 같습니다.

AI가 짠 코드를 같은 AI가 검토하면 자기 실수를 잘 못 봅니다. 사람이 자기 글의 오타를 못 잡는 것과 똑같습니다. 그래서 민감한 변경 — 인증·트랜잭션·권한·결제처럼 한 번 틀리면 비싼 영역 — 에는 독립적인 두 번째 모델로 코드를 리뷰하게 했습니다. “200 IQ의 까다로운 동료”에게 한 번 더 보여주는 셈입니다.

규칙을 “강제”한다는 건 결국 **훅(hook)**입니다. 파일을 쓰기 직전, 커밋하기 직전에 검사 스크립트가 끼어들어, 조건을 안 맞추면 그 자리에서 차단합니다. 권고가 아니라 물리적 차단입니다.

  1. 테스트 없이 핵심 파일 작성 → 차단. “테스트 먼저 보여라.”
  2. 같은 파일을 짧은 시간에 세 번 넘게 수정 → 네 번째를 차단. “디버깅 방향을 재고하라.” (같은 실수를 반복하는 패턴을 멈춤)
  3. 거대 파일을 더 키움 → 차단. (다음 절의 ratchet)
  4. 이미 있는 걸 또 만드는 중복 테스트 작성 → 차단. “기존 걸 먼저 찾아라.”

린트(lint)로 코드 스타일을 잡되, 절대 기준이 아니라 ratchet 방식을 썼습니다. ratchet은 한쪽으로만 돌아가는 톱니(자전거 뒷바퀴, 케이블타이를 떠올리면 됩니다)입니다. 파일·함수 크기를 현재 상태로 동결하고, “지금보다 나빠지는 것”만 금지합니다.

네 겹을 한눈에 — 무엇을, 언제, 어떻게

섹션 제목: “네 겹을 한눈에 — 무엇을, 언제, 어떻게”
루프막는 것거는 시점판정
TDD테스트 없는 구현핵심 파일 작성 직전RED 흔적 없으면 차단
Codex 리뷰자기 점검의 사각지대민감 변경 직후독립 모델이 결함 지적
hook규칙 위반·반복 실수작성·커밋 직전조건 미충족 시 차단
lint·ratchet파일·함수 비대화커밋 직전현재보다 커지면 차단

네 루프는 따로 노는 게 아니라, 하나의 변경이 흘러가는 동안 순서대로 끼어듭니다. 어떤 핵심 서비스에 기능을 더한다고 해보겠습니다.

  1. 코드 작성 시도 — AI가 서비스 파일에 새 함수를 쓰려 합니다. TDD 훅이 가로막습니다: “이 변경에 대한 실패 테스트(RED)부터 보여라.”
  2. 테스트 먼저 — 실패하는 테스트를 쓰고 RED를 확인한 뒤, 통과시키는 코드를 짭니다(GREEN). 이제 작성이 허용됩니다.
  3. 민감 변경 리뷰 — 권한·트랜잭션이 얽힌 변경이라, *독립 모델(Codex)*이 한 번 더 봅니다. “예외 경로에서 권한 체크가 빠졌다”를 잡아냅니다.
  4. 커밋 시도 — 고친 뒤 커밋하려 하자, ratchet 린트가 검사합니다: “이 파일이 동결된 크기보다 커졌다 — 차단.” 함수를 분해하거나 facade로 나눈 뒤 다시 커밋합니다.
  5. 통과 — 네 게이트를 다 통과한 변경만 저장소에 들어갑니다. 사람이 일일이 챙기지 않아도, 품질의 하한선이 지켜집니다.

주목할 점은, 이 다섯 단계 어디에도 “사람이 규칙을 기억해서 챙기는” 대목이 없다는 것입니다. 루프가 닫혀 있으니, 잊어도 게이트가 대신 막습니다. 이게 “규칙을 문서로 두는 것”과 “규칙을 루프로 닫는 것”의 결정적 차이입니다.

루프는 “처음부터 완벽”이 아니라 “보강”이다

섹션 제목: “루프는 “처음부터 완벽”이 아니라 “보강”이다”

이 게이트들을 한 번에 다 깐 게 아닙니다. 어떤 실패 패턴이 반복될 때마다, 거기에 맞는 센서를 하나씩 추가했습니다.


이 글은 SL.AIMS를 만들며 겪은 현장 회고 중 하나입니다. 전체 그림은 〈사례연구: SL.AIMS〉에, 이 루프가 떠받치는 큰 그림은 〈하네스〉에, 솎아낸 규칙들의 출처는 〈방법론 이식〉에 있습니다.