본문으로 건너뛰기
페이지 목차
이 페이지에서 검색

AI 드리븐

이 페이지에 묻기

AI 드리븐 · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.

생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.

AI · DEVELOPMENT

AI 드리븐

생성 수정

요구사항과 역할 정의부터 구현·검증·배포·운영까지, AI와 함께 개발하며 사람이 판단할 기준을 정리합니다.

26개 문서 · 2일차 · 14 / 26

13차시 · 검증 ① 코드·동작 점검

지도 위치 : 2일차 · 구현과 검증 · 검증 | 이전: 12차시 데이터 관리 역할 | 다음: 14차시 검증 ② 보안 점검과 차단 키워드 : 코드 검토와 동작 검증의 분리, 경계·실패 상황, 동시 요청 문제

이 차시를 다 읽으면

  1. 정적 검증(코드 검토) 과 동적 검증(동작 검증) 을 구별하고, 각각이 잘 찾는 문제와 놓치는 문제를 말할 수 있다.
  2. 검증 역할 두 개(리뷰어 · QA)의 권한 차이 를 만드는 자 ↔ 검증하는 자 축으로 설명할 수 있다.
  3. 인원 · 날짜 · 남은 자리에 대한 경계값 목록 을 직접 쓸 수 있다.
  4. 경쟁 상태 를 유와 종차로 정의하고, "조회 → 판단 → 저장" 코드가 동시 요청에서 실패하는 과정을 그림으로 설명할 수 있다.
  5. 경쟁 상태의 해결책 세 가지를 주 방어 / 마지막 방어 로 나누고, 동시성 시험 결과를 숫자 두 개 로 판정할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1읽는가, 실행하는가정적 검증 — 코드를 읽고 판단동적 검증 — 실행하고 결과 확인코드 검토 ↔ 동작 검증정적 ↔ 동적 검증 (⑧의 파생)
2누가 검증하는가만든 역할 자신다른 맥락 · 제한된 권한의 역할같은 맹점을 공유하는가만드는 자 ↔ 검증하는 자 (⑤의 파생)
3어떤 경우를 시험하는가정상 경로 — 적당한 값 하나경계 · 실패 — 끝자락 값, 끊김, 오류AI 코드의 버그가 숨는 곳이 차시의 축
4요청이 하나씩인가, 동시에인가순차 — 한 명씩동시 — 같은 순간 여러 명혼자 시험하면 안 보이는 경쟁 상태이 차시의 축
5완료를 무엇으로 판정하는가"테스트 다 통과했습니다"재현 명령 + 출력 + DB의 숫자검증 보고를 믿을 수 있는가증거 ↔ 주장

이 차시가 답하는 질문은 "AI가 만든 코드의 버그는 어디에 숨는가, 그리고 누가 어떻게 찾는가" 입니다. AI가 만든 코드는 정상 경로에서는 거의 항상 동작 합니다. 데모에서는 문제가 보이지 않습니다. 실제 사고는 0명, 최댓값, 네트워크 끊김, 두 사람이 동시에 누르는 순간(축 3 · 4의 오른쪽)에 납니다. 앞에서 배운 "만드는 자와 검증하는 자의 분리"(7차시)를 이번에는 화면이 아니라 코드에 적용합니다.


1. 정적 검증과 동적 검증

1.1 정의와 경계

정적 검증 (코드 검토) — [검증 방법]인데, [ 코드를 실행하지 않고 읽어서 판단한다 ]는 점에서 실제로 돌려 보는 동적 검증과 구별된다.

동적 검증 (동작 검증) — [검증 방법]인데, [ 실제로 실행해 나온 결과로 판단한다 ]는 점에서 읽어서 판단하는 정적 검증과 구별된다.

코드 검토 (정적)동작 검증 (동적)
방법코드를 읽고 판단실행하고 결과 확인
잘 찾는 것인가 누락, 명세 불일치, 에러 처리 빠짐, "조회 → 판단 → 저장" 패턴, 구조 문제실제 응답 오류, 연동 문제, 동시성 문제
한계실제로 도는지는 모름시험한 경우만 확인됨
담당리뷰어 (code-reviewer, 읽기 전용)QA (qa, 실행 권한 있음, 앱 코드 수정 불가)

둘 다 필요합니다. 코드 검토만 하면 "논리상 맞아 보이는" 버그를 놓치고, 동작 검증만 하면 시험하지 않은 경로를 놓칩니다.

1.2 반례 — 이건 검증이 아닙니다

대상왜 아닌가
구현 에이전트의 "테스트 다 통과했습니다"만든 자의 주장 . 0절 축 2의 왼쪽 + 축 5의 왼쪽
정상 예약 한 번 눌러 보고 "잘 됩니다"동적 검증이긴 하지만 축 3의 왼쪽만 시험
같은 대화 안에서 "방금 만든 코드 검토해줘"만든 맥락을 그대로 가진 채 검토 — 같은 맹점

💡 코드를 읽지 않는 사람에게 이 표의 의미 — 두 검증 중 동작 검증은 내가 직접 할 수 있습니다. 코드 검토는 리뷰 역할에게 맡기고, 내 시간은 동작 검증과 그 결과 숫자를 보는 데 씁니다.


2. 검증하는 자를 분리하기

앞에서 배운 하위 에이전트(2차시)와 역할 정의(5차시)로 검증 역할 둘을 만듭니다. 핵심은 권한(tools) 입니다.

# .claude/agents/code-reviewer.md
tools: Read, Grep, Glob
점검: 명세 일치, 입력 검증, 인가(본인 데이터만), 트랜잭션 범위, 에러 형식,
      조회-판단-저장 패턴
보고: [심각도 | 파일:줄 | 문제 | 사용자에게 생기는 피해 한 줄]

# .claude/agents/qa.md
tools: Read, Bash, Grep, Glob   (앱 코드 수정 불가, tests/ 폴더만 작성)
시험: 정상 1 + 경계값 + 실패 상황 + 동시 요청 20개
보고: [시험한 경우 | 기대 결과 | 실제 결과 | 재현 명령]

🔍 읽는 포인트 : tools: 줄에 Write · Edit가 없다 = 코드를 고칠 수 없다. 리뷰어는 읽기만, QA는 실행까지만 합니다.

원칙이유
검증자는 발견하면 보고만 하고 고치지 않는다고치는 순간 검증자가 만드는 자가 되어 다시 같은 맹점을 공유
고치는 일은 구현 역할이 한다검증자의 보고 → 구현 역할 수정 → 검증자 재시험
QA는 tests/에만 쓸 수 있다시험이 실패할 때 앱 코드 대신 시험을 고치는 일을 막음 (17차시)

3. 경계와 실패

3.1 경계값 — 값의 끝자락

입력시험할 값
인원 headcount (1~4)0, 1, 4, 5, -1, 1.5, "abc", 빈 값
남은 자리정확히 1 남았을 때, 0일 때
날짜오늘, 지난 날짜, 취소 기한 당일 자정 직전 · 직후
문자열빈 문자열, 아주 긴 문자열, 이모지, 특수문자
목록0개, 1개, 한 페이지를 딱 채우는 개수

⭐ 이 표는 코드 지식이 아니라 서비스에 대한 이해 에서 나옵니다. "인원은 몇 명까지?", "취소는 언제까지?"를 정한 사람은 나(3차시의 인수 기준)입니다. 그래서 경계값 표는 내가 직접 쓰고, 시험은 AI에게 시킵니다.

3.2 실패 상황 — "이게 실패하면?"

실패기대하는 모습
DB 연결이 끊김500과 일반 메시지. 내부 정보(SQL, 파일 경로) 노출 없음 (14차시)
결제 대행사가 응답하지 않음예약은 결제 대기 상태로 남고 다시 시도 가능 (16차시)
예약 생성 다음 단계에서 오류자리만 줄고 예약이 없는 상태가 남지 않음 — 트랜잭션 (12차시 4절)

4. ⭐ 경쟁 상태 — 동시 요청 문제

4.1 정의와 그림

경쟁 상태 (Race Condition) — [동시성 버그]인데, [ 여러 요청이 같은 데이터를 동시에 읽고 바꿀 때, 실행 순서가 겹치는 방식에 따라 결과가 틀어진다 ]는 점에서 요청 하나만으로 재현되는 일반 버그와 구별된다.

남은 자리: 1

  사용자 A                          사용자 B
  ① 남은 자리 조회 → 1                ① 남은 자리 조회 → 1
  ② 1 > 0 이니 예약 가능              ② 1 > 0 이니 예약 가능
  ③ 남은 자리 = 0 저장, 예약 생성      ③ 남은 자리 = 0 저장, 예약 생성

결과: 자리 1개에 예약 2개 (초과 예약)

🔍 읽는 포인트 : A의 ①과 ③ 사이에 B의 ①이 끼어든 것이 전부입니다. 각자의 코드는 혼자서는 완벽합니다.

AI가 흔히 만드는 "조회 → 판단 → 저장" 코드는 혼자 시험할 때 완벽하게 동작합니다. 그래서 일부러 동시에 요청을 보내 봐야 드러납니다(0절 축 4).

4.2 반례 — 이건 경쟁 상태가 아닙니다

대상왜 아닌가
같은 사용자가 결제 버튼을 두 번 눌러 예약이 두 개중복 요청 문제 — 같은 의도가 두 번 들어옴. 해결은 멱등성 (16차시)
인원 5명 예약이 통과됨요청 하나로 재현되는 입력 검증 누락 (10차시)
"드물게 일어나는 일"⚠️ 인기 클래스 오픈 시각에는 매번 일어납니다

4.3 해결책 — 주 방어와 마지막 방어

#방법하는 일역할
1조건부 갱신을 한 문장으로조회와 차감을 DB가 한 번에 처리 — 사이에 끼어들 틈이 없음주 방어
2행 잠금트랜잭션 안에서 SELECT ... FOR UPDATE로 그 회차를 잠그고 판단. 다른 요청은 기다림주 방어 (1의 대안)
3DB 제약조건CHECK (remaining >= 0) — 1 · 2에 버그가 있어도 음수를 거부마지막 방어선 (12차시 3.2)
UPDATE sessions SET remaining = remaining - 1
WHERE id = $1 AND remaining >= 1;
-- 바뀐 행이 0개면 "자리 없음" → 409 SOLD_OUT

🔍 읽는 포인트 : WHERE ... remaining >= 1 — "자리가 있으면 줄여라"를 한 문장으로 말합니다. 조회와 저장 사이의 틈(4.1의 그림)이 사라집니다.

💡 비유는 마지막에 — 공연장 매표소 두 곳이 같은 좌석표를 각자 장부로 확인하고 팔면 한 좌석이 두 번 팔립니다. 해결은 중앙 전산 한 곳에서 "비어 있으면 팔림 처리"를 한 번에 하는 것입니다.


5. 동시성 시험

# 남은 자리 1인 회차에 20개 요청을 동시에 보냄
for i in $(seq 1 20); do
  curl -s -o /dev/null -w "%{http_code}\n" -X POST localhost:4000/reservations ... &
done; wait
# 기대: 201이 정확히 1개, 나머지는 409
# 그리고 DB에서 해당 회차 예약 수가 정확히 1인지 확인

🔍 읽는 포인트 : 끝의 &가 "기다리지 않고 동시에" 보내는 표시입니다. 기대 줄의 숫자 두 개 만 보면 됩니다.

⭐ 판정은 숫자 두 개 로 합니다.

숫자정상
① 성공(201) 응답 개수1
② DB에 실제로 생긴 예약 개수1

둘 중 하나라도 2 이상이면 경쟁 상태가 있는 것입니다. ①은 1인데 ②가 2라면 응답과 실제 데이터가 어긋난 더 나쁜 경우입니다.

앞으로 다시 만납니다 — 이 동시성 시험은 17차시에서 자동 테스트로 옮겨져 변경 때마다 다시 돌고, 19차시의 자동 검사 관문에서 통과 조건이 됩니다.


6. 클래스온에 적용하면

시점리뷰어에게QA에게
POST /reservations 구현 직후조회-판단-저장 패턴이 있는가, 트랜잭션 범위경계값 표(3.1) + 동시 요청 20개
예약 취소 구현 직후인가(본인 예약만)취소 기한 자정 직전 · 직후, 자리 복구 확인
리뷰 지적이 너무 많거나 어려울 때"사용자에게 실제 피해가 생기는 것 / 나중에 고쳐도 되는 것 으로 나눠줘"—

7. 실습 — 맡기고 검수하기

지시

qa 역할로 진행해줘. 앱 코드는 수정하지 마.
1. 남은 자리 1인 회차를 만들고, 예약 요청 20개를 동시에 보내.
   결과로 ① 201 응답 개수 ② DB에 실제로 생긴 그 회차의 예약 개수, 이 두 숫자를 먼저 보여줘.
2. 아래 경계값 표대로 시험하고 [입력 | 기대 | 실제 응답 | 통과?] 표로 보고해줘.
   (내가 쓴 경계값 표를 여기 붙임)
3. DB를 멈춘 상태에서 예약 요청을 보내고 응답 원문을 보여줘.
모든 시험의 재현 명령과 실행 출력 원문을 붙여줘. 실패한 것이 있으면 고치지 말고 보고만 해.

(별도로) code-reviewer 역할로 POST /reservations를 검토하고,
지적을 [사용자에게 실제 피해 | 나중에 고쳐도 됨]으로 나눠 보고해줘.

받을 증거

  • 동시성 시험의 숫자 두 개 와 실행 출력 원문
  • 경계값 결과 표와 재현 명령
  • DB 중단 시 응답 원문
  • 리뷰 지적을 피해 기준으로 나눈 표

내가 직접 확인할 것

볼 것이걸로 아는 것 / 왜 내가 보는가
동시성 시험의 숫자 두 개가 둘 다 1 인가경쟁 상태 여부. 이 차시에서 가장 중요한 숫자
12차시의 DB 조회 도구로 그 회차의 예약 행을 내가 직접 센다AI가 보고한 ②번 숫자를 내 눈으로 확인 (README 9.1의 행동 시험)
경계값 표를 내가 썼는가서비스 규칙을 아는 사람은 나. AI가 쓰면 규칙과 다른 경계를 시험할 수 있음
DB 중단 시 응답에 SQL · 파일 경로가 보이는가보이면 14차시의 정보 노출
QA가 앱 코드를 바꿨는가 (변경 파일 목록)바꿨다면 검증자가 만드는 자가 된 것 (2절)
리뷰 지적 중 "실제 피해" 칸이것부터 구현 역할에게 넘김

부록 A. 스스로 확인하기

#질문답이 있는 곳
1정적 검증과 동적 검증을 유와 종차로 정의하면?1.1
2코드 검토와 동작 검증이 각각 잘 찾는 문제와 한계는?1.1
3"테스트 다 통과했습니다"가 검증이 아닌 이유를 두 축으로 말하면?1.2
4리뷰어와 QA의 권한은 어떻게 다르고, 왜 검증자는 고치지 않는가?2
5인원(1~4) 입력의 경계값 목록은? 이 표를 누가 써야 하는가?3.1
6경쟁 상태를 정의하고 "조회 → 판단 → 저장"이 실패하는 과정을 설명하면?4.1
7경쟁 상태와 중복 요청은 어떻게 다른가?4.2
8해결책 세 가지와 각각의 역할(주 방어 / 마지막 방어)은?4.3
9동시성 시험을 판정하는 숫자 두 개는?5

부록 B. 자주 하는 실수

실수바로잡기
구현 에이전트의 "테스트 통과" 보고를 그대로 믿는다❌ 검증은 다른 역할이, 출력 원문으로 (1.2)
경계값을 "적당한 값 하나"로 시험❌ 끝자락 값 목록 전부 (3.1)
동시 요청 문제를 "드물다"며 넘긴다⚠️ 인기 클래스 오픈 시각에는 매번 일어납니다 (4.2)
검증자가 발견하자마자 직접 고친다❌ 보고하고, 고치는 건 구현 역할 (2)
CHECK 제약조건 하나로 경쟁 상태를 해결했다고 본다⚠️ 그건 마지막 방어선. 주 방어(조건부 갱신 · 잠금)가 함께 (4.3)
201 개수만 보고 끝낸다⭕ DB의 실제 예약 수까지 두 숫자 (5)

부록 C. NotebookLM 복습 프롬프트

이 13차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"정적 검증과 동적 검증", "검증자를 분리하는 권한 설계", "경쟁 상태와 중복 요청의 차이", "동시성 시험의 숫자 두 개"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.