정산 백엔드를 개발하면서 AI 코딩 도구를 팀에 도입했습니다. 처음 몇 주는 오히려 리뷰 부담이 늘었습니다. 코드는 빨리 나오는데 그 코드를 믿을 근거가 없었기 때문입니다. 그래서 생성 속도를 올리는 대신 각 단계에 검증과 중단 조건을 넣는 쪽으로 방향을 틀었습니다. 그 과정을 정리합니다.
TL;DR
- AI를 코드 생성기로 쓰면 속도는 오르지만 검증 비용이 그만큼 늘어납니다. 돈을 다루는 도메인에서는 이 거래가 남지 않습니다.
- Rules, Skills, Agents, Hooks 네 계층으로 나누고 계획부터 PR까지 단계마다 권한 경계와 중단 조건을 넣었습니다.
- 검증은 반드시 격리된 컨텍스트에서 했습니다. 자기가 쓴 코드를 같은 세션에서 리뷰하면 확증편향이 그대로 나옵니다.
- 세션에서 발생한 마찰을 모아 규칙으로 승격시키는 루프를 돌렸습니다. 팀원 4명의 222개 세션에서 328개 이벤트를 분류했습니다.
- 개수를 늘리는 건 목표가 아니었습니다. 실제로 값을 준 건 "틀린 걸 빨리 드러내는" 구조였습니다.
문제 정의: 빠른 코드가 왜 부담이 됐나
정산 시스템은 조용히 틀리는 게 제일 무섭습니다. 예외가 터지면 알림이 오지만 금액이 조금 다르거나 일부 행이 빠지면 아무 일도 일어나지 않습니다. 며칠 뒤 정산 담당자가 발견합니다.
AI에게 작업을 맡기기 시작하면서 네 가지 마찰이 반복됐습니다.
- 범위가 멋대로 넓어집니다. 버그 하나를 고치라고 했는데 주변 코드까지 리팩터링해 옵니다. 변경이 커지면 리뷰가 실질적으로 불가능해집니다.
- 검증 없이 완료를 보고합니다. 테스트를 돌렸다는 말과 테스트가 통과했다는 말이 다른데, 후자를 확인하지 않고 전자만 말하는 경우가 있었습니다.
- 같은 실수를 세션마다 반복합니다. 어제 지적한 걸 오늘 새 세션이 모릅니다.
- 그럴듯한 가설로 시작합니다. 로그를 보기 전에 원인을 추측하고 그 추측에 맞춰 코드를 고칩니다.
넷 다 "AI가 코드를 못 쓴다"는 문제가 아닙니다. 판단 과정에 게이트가 없다는 문제였습니다.
접근: 네 계층으로 나눈다
쓰는 도구는 Claude Code입니다. 구성 요소를 네 가지 역할로 갈라 배치했습니다.
| 계층 | 역할 | 로드 시점 |
|---|---|---|
| Rules | 항상 지켜야 하는 절대 규칙 | 매 세션 자동 |
| Skills | 특정 작업의 절차서 | 해당 작업 때 |
| Agents | 격리된 컨텍스트의 검증자 | 검증 단계에서 호출 |
| Hooks | 기계적 차단 장치 | 도구 실행 직전 |
Rules와 Hooks를 분리한 게 핵심입니다. 규칙을 문서로 적어두면 지켜지기도 하고 안 지켜지기도 합니다. 반드시 막아야 하는 건 문서가 아니라 훅이 막습니다.
Rules: 지켜야 하는 것을 짧게
규칙은 길게 쓰면 안 지켜집니다. 스코프 제약처럼 위반 시 피해가 큰 것만 남겼습니다.
## 스코프 규칙
- "분석해줘" / "리뷰해줘" = 코드 읽고 정리만. 코드 수정 금지
- "수정해줘" = 지정된 파일·레이어만. 범위 확장 전 반드시 확인
- 요청하지 않은 리팩터링·테스트 커버리지 개선 제안 금지
- 같은 패턴의 버그를 여러 파일에서 고칠 때는 대상 파일 목록 먼저 제시 → 승인 후 수정
## 디버깅 규칙
- 가설을 세우기 전에 증거(로그, 쿼리 결과, 스택트레이스)를 먼저 수집
- 증거 없이 원인을 추측하지 않음
- 2회 실패 시 중단하고 추가 정보 요청마지막 줄이 의외로 효과가 컸습니다. 실패한 접근을 변형해서 계속 시도하는 패턴이 있는데, 횟수 제한을 박아두면 그때 사람이 개입합니다.
Skills: 절차를 고정한다
같은 종류의 작업을 반복하면 매번 다른 순서로 진행됩니다. 순서를 문서로 고정했습니다. 계획 수립, 빌드 검증, 보안 점검, JPA 쿼리 확인, 코드 리뷰 같은 것들입니다. 지금 누적 15개입니다.
Skill이 값을 준 건 "무엇을 하는가"보다 "무엇을 하기 전에 무엇을 확인하는가" 였습니다. 예를 들어 구현 Skill에는 이런 줄이 들어갑니다.
- 구현 전 반드시 유사 기능 2~3개를 검색해 패턴을 확인한 뒤 착수
- SQL·테스트 데이터를 바꿀 때는 컬럼명이 실제 스키마에 있는지 먼저 확인
- 존재하지 않는 메서드·enum·타입을 언급하지 않음. 검색으로 실재 확인 후 언급세 줄 다 "환각을 막는 절차"입니다. 금지만 적으면 안 지켜지고 확인 방법을 같이 적으면 지켜집니다.
Agents: 검증은 격리해서
가장 크게 달라진 부분입니다. 처음에는 구현한 세션에서 그대로 리뷰를 시켰습니다. 결과가 좋지 않았습니다. 자기 결정을 정당화하는 방향으로 리뷰가 흘러갑니다.
그래서 검증을 별도 컨텍스트로 뺐습니다. 검증 Agent는 구현 과정을 모르고 결과물과 요구사항만 봅니다. "문제가 없는지 확인하라"가 아니라 "반례를 찾아라" 로 지시를 뒤집었습니다.
지금 전문 Agent가 11개입니다. 마이그레이션 검증, 금액 계산 검증, CSV 포맷 검증, OpenAPI 명세 일치, 권한 부착 확인, 프론트와 백엔드 계약 검증 같은 축으로 나눠 뒀습니다. 정산 도메인에서 조용히 틀리는 지점들이 그대로 축이 됐습니다.
Hooks: 문서로 안 되는 건 막는다
되돌리기 힘든 명령은 훅으로 차단했습니다. 강제 푸시나 하드 리셋 같은 것들입니다.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/block-dangerous-git.sh" }]
}
]
}
}훅은 판단하지 않습니다. 패턴이 맞으면 막습니다. 이 단순함이 장점입니다.
단계 게이트를 넣는다
네 계층을 흐름에 배치했습니다.
계획 ──▶ TDD ──▶ 검증 ──▶ 코드 리뷰 ──▶ PR
│ │ │ │ │
│ │ │ │ └ 템플릿 준수, 사람 승인
│ │ │ └ 격리 Agent가 반례 탐색
│ │ └ 실제 실행 결과로만 통과 판정
│ └ 실패하는 테스트를 먼저 확인
└ 계획을 문서로 확정. 승인 없이 다음 단계로 못 감각 화살표에 중단 조건을 뒀습니다. 예를 들어 계획 단계에서 영향 파일 목록이 예상보다 넓으면 멈추고 물어봅니다. 검증 단계에서는 "테스트를 돌렸다"가 아니라 실제 출력이 있어야 통과로 봅니다.
설계 판단이 갈릴 때는 한 안을 밀지 않고 여러 관점에서 교차 검토했습니다. 합의한 내용은 문서로 확정하고 최종 결론은 실제 코드와 운영 자료에서 확인했습니다.
개선 루프: 마찰을 규칙으로 승격시킨다
여기가 제일 재미있었습니다. 규칙을 미리 잘 설계하려고 하면 실패합니다. 실제로 부딪힌 것만 규칙이 될 자격이 있습니다.
팀원 4명의 세션 222개를 모아 마찰이 생긴 지점 328개를 뽑고 유형별로 분류했습니다. 상위에 올라온 건 이런 것들이었습니다.
- 증거 없이 세운 잘못된 가설
- 요청 범위를 넘은 변경
- 리뷰에서 실재하지 않는 대상을 지적한 오탈
- 기준 브랜치를 잘못 잡아 생긴 드리프트
각 유형을 Rules에 재발 방지 조건으로 적거나, 기계적으로 막을 수 있으면 Hook으로 옮겼습니다. 이 루프가 돌기 시작하면서 같은 실수가 반복되는 빈도가 눈에 띄게 줄었습니다.
정량 지표도 봤습니다. 도구를 정착시킨 뒤 제 월 처리 티켓이 5건에서 21건 구간으로 올라갔습니다. 다만 이 숫자를 Harness의 성과라고 말하기는 어렵습니다. 앞 구간이 입사 직후 온보딩 기간이었고 티켓을 더 잘게 쪼갠 영향도 있습니다. 인과를 주장할 수 있는 데이터는 아니고 그 구간을 실제로 소화했다는 사실 정도로 봅니다.
알게 된 한계
규칙이 늘면 비용이 됩니다. Rules는 매 세션 로드되므로 길어지면 그만큼 컨텍스트를 먹습니다. 항상 필요한 것만 Rules에 두고 나머지는 Skill로 내려야 합니다. 저도 한 번 비대해져서 정리했습니다.
훅은 과잉 차단을 부릅니다. 위험 패턴을 넓게 잡으면 정상 작업까지 막힙니다. 그러면 사람이 훅을 우회하기 시작하고 그 순간 훅은 무력해집니다. 좁게 잡고 필요할 때 넓히는 편이 낫습니다.
검증 Agent도 틀립니다. 반례를 찾으라고 지시하면 없는 문제를 만들어 옵니다. 그래서 검증 결과를 그대로 신뢰하지 않고 지적된 대상이 실제로 코드에 있는지부터 확인합니다. 이 확인 절차 자체를 리뷰 Skill에 넣었습니다.
개수는 지표가 아닙니다. Skills 15개, Agents 11개라고 썼지만 이 숫자로 뭘 판단할 수는 없습니다. 쓰이지 않는 Skill도 있고 만들었다가 지운 것도 있습니다. 의미가 있는 건 "어떤 실수가 다시 안 나게 됐는가"입니다.
마무리
돌아보면 방향을 한 번 크게 틀었습니다. 처음에는 AI로 더 빨리 만들려고 했고 지금은 AI로 더 빨리 틀린 걸 드러내려고 합니다. 정산처럼 조용히 틀리면 손해가 큰 도메인에서는 후자가 훨씬 남는 거래였습니다.
한 가지 덧붙이면, 이 구조는 도메인 지식이 어딘가에 정리돼 있어야 제대로 돕니다. 검증 Agent가 "이 금액 계산이 맞는가"를 판단하려면 기준을 알아야 하니까요. 그래서 도메인 지식을 별도 위키로 유지하는 작업을 병행했고 그 이야기는 정산 멀티레포 도메인 지식을 LLM Wiki로 유지하기에 정리했습니다.
'AI' 카테고리의 다른 글
| 정산 멀티레포 도메인 지식을 LLM Wiki로 유지하기 (0) | 2026.07.27 |
|---|