WEBBOOK CHAPTER

Codex로 구축하는 AI 개발팀: 6장. 요구를 실행 가능한 명세로 바꾼다

6장. 요구를 실행 가능한 명세로 바꾼다

다음은 여러 현장에서 반복된 패턴을 합친 합성 사례로, 등장하는 숫자는 설명을 위한 예시 수치다.

“주문 목록에 총액을 보여 주세요. 기존 방식대로요.” 사람은 화면을 보고 대략 뜻을 짐작한다. 에이전트는 선택해야 한다. 세금과 배송비를 포함하는가? 환불된 항목은 빼는가? 통화 반올림은 어디서 하는가? 값이 없으면 0인가, 오류인가? 질문에 답이 없는데도 구현이 시작되면 추측이 제품 규칙이 된다.

명세 주도 개발에서 명세는 길고 완벽한 문서가 아니다. 구현 전에 불확실한 결정을 드러내고, 구현 뒤에는 결과를 판정할 수 있게 하는 공동 계약이다.

이번 장의 약속

  • 요구, 설계, 작업, 테스트의 역할을 분리한다.
  • 자연어 규칙을 예시·결정표·불변 조건으로 정밀하게 만든다.
  • 명세의 수용 기준을 자동 테스트와 추적한다.
  • 모호함이 남았을 때 안전하게 차단하고 질문한다.

명세가 답해야 할 여섯 질문

작은 변경 명세도 다음 질문에 답한다.

  1. 지금 이 변화가 필요한가?
  2. 누가 어떤 상황에서 사용하며 어떤 결과를 얻는가?
  3. 무엇이 범위 안과 밖인가?
  4. 어떤 규칙과 예외가 적용되는가?
  5. 무엇으로 완료를 판정하는가?
  6. 성능·보안·호환성 같은 제약은 무엇인가?

구현 방법을 지나치게 고정하지 않는다. 제품 의도와 반드시 지켜야 할 제약을 명확히 하되, 내부 함수명과 파일 구조는 설계 문서나 작업 계획에서 다룬다.

요구, 명세, 계획, 테스트를 섞지 않는다


요구: 사용자가 얻을 가치와 문제
명세: 관찰 가능한 동작과 제약
설계: 책임·경계·데이터 흐름의 선택
계획: 구현 순서와 작업 소유권
테스트: 명세를 실행해 얻는 증거
요구, 명세, 설계, 계획, 테스트가 왼쪽에서 오른쪽으로 흐르고 AC-01, AC-02, AC-03 수용 기준이 테스트 증거에서 명세로 되돌아가는 양방향 연결.
요구, 명세, 설계, 계획, 테스트가 왼쪽에서 오른쪽으로 흐르고 AC-01, AC-02, AC-03 수용 기준이 테스트 증거에서 명세로 되돌아가는 양방향 연결.

그림 6-1. 요구→명세→설계→계획→테스트의 역할을 분리하고, AC 식별자로 증거를 다시 명세에 역추적한다.

테스트가 명세의 중요한 부분을 실행할 수 있지만 테스트 코드 자체가 유일한 명세가 되면 비개발자가 의미를 확인하기 어렵다. 반대로 자연어만 있고 테스트와 연결되지 않으면 시간이 지나며 구현과 갈라진다. 짧은 명세와 자동 검사를 양방향으로 연결한다.

작지만 판정 가능한 명세 템플릿


# 주문 조회의 총액

## 문제와 결과
고객 지원 담당자가 주문 상세에서
결제 기준 총액을 바로 확인한다.

## 범위
- 포함: 주문 조회 API 응답의 `total` 필드
- 제외: 목록 화면 표시, 다중 통화 환산,
  과거 데이터 마이그레이션

## 용어
- 품목 소계: 각 품목의 단가 × 확정 수량의 합
- 총액: 품목 소계 - 주문 할인 + 배송비 + 세금

## 규칙
1. 금액은 통화의 최소 단위인 정수로 전달한다.
2. 취소된 품목은 품목 소계에서 제외한다.
3. 전액 환불 여부는 원래 주문 총액을 바꾸지 않는다.
4. 계산에 필요한 필드가 없으면 0으로 추정하지 않는다.
   대신 데이터 오류를 반환한다.

## 수용 예시
- 품목 10,000원×2, 할인 3,000원, 배송비 2,500원, 세금 0원 → 19,500원
- 모든 품목 취소, 배송비 취소 → 0원
- 통화 코드 누락 → `ORDER_MONEY_INVALID`

## 비기능 제약
- 기존 응답 필드는 변경하지 않는다.
- 주문 100개 조회의 상위 95% 응답 시간이
  기준선보다 10% 넘게 악화되지 않는다.

## 미결정
- 혼합 통화 주문은 현재 제품에서 생성 가능한가?
  — 제품 책임자 확인 필요

## 증거
- `test/orders/total.test.js`
- `test/contracts/order-response.test.js`

숫자는 예시다. 실제 책 실습에서는 예제 애플리케이션의 기준값을 사용한다. 중요한 것은 성공 예뿐 아니라 예외와 잘못된 입력을 함께 명시하는 것이다.

예시는 추상 규칙의 빈틈을 드러낸다

“정확한 총액을 반환한다”는 문장은 검증할 수 없다. 구체적인 예시를 만들면 결정하지 않은 부분이 드러난다.

품목 할인 배송비 세금 상태 기대 총액
20,000 3,000 2,500 0 확정 19,500
20,000 25,000 0 0 확정 ?
20,000 0 2,500 2,000 품목 취소 ?
없음 0 0 0 생성 중 ?

물음표가 제품 결정 목록이다. 구현자가 합리적이라고 느끼는 값을 고르는 대신 명세 승인자에게 돌려보낸다.

예시는 다음 범주를 포함한다.

  • 가장 흔한 정상 경로
  • 경계값: 0, 최대, 최소 단위, 빈 목록
  • 상태 전이: 생성, 확정, 취소, 환불
  • 잘못된 입력과 기대 오류
  • 기존 동작과의 호환
  • 권한과 데이터 노출

결정표로 규칙 조합을 다룬다

조건이 세 개만 되어도 자연어 문단은 조합을 놓치기 쉽다.

주문 확정 품목 취소 통화 유효 행동
아니오 총액 반환
취소 품목 제외 후 반환
아니오 잠정 총액 반환 안 함
아니오 ORDER_MONEY_INVALID

-는 결과에 영향을 주지 않는 조건이다. 표의 각 행을 테스트 사례와 연결하면 빠진 조합과 중복 규칙을 찾기 쉽다.

불변 조건은 생성 방법과 무관한 울타리다

예시가 특정 입력을 다룬다면 불변 조건은 넓은 입력 공간에서 항상 지켜야 할 성질이다.


총액은 안전한 정수 범위를 벗어나지 않는다.
취소되지 않은 품목을 추가하면,
다른 조건이 같을 때 소계는 감소하지 않는다.
응답의 통화 코드는 총액 계산에 사용한 통화와 같다.
권한 없는 사용자는 총액을 포함한 주문을 조회할 수 없다.

불변 조건은 속성 기반 테스트, 구조 검사, 보안 테스트의 원료가 된다. 모든 것을 자동화할 수 없어도 리뷰 체크리스트에 명시하면 ‘좋아 보임’보다 강한 판정이 된다.

모호함을 등급으로 다룬다

모든 미결정이 작업을 막아야 하는 것은 아니다.

등급 처리
A: 안전·제품 의미 영향 할인 하한, 권한, 데이터 삭제 시작 전 반드시 결정
B: 공개 계약 영향 필드 이름, 오류 코드, 호환성 구현 전 결정 또는 명시적 승인
C: 내부 구현 선택 지역 변수명, 작은 함수 분리 에이전트가 선택하고 기록
D: 가역적 표현 내부 로그 문구 기본값 사용 가능

등급 A와 B가 비어 있으면 BLOCKED다. C와 D는 저장소 규칙 안에서 선택할 수 있지만, 나중에 중요한 근거가 될 결정은 인계 문서에 남긴다.

명세 자체도 버전과 상태를 가진다

설계 예(실행용 아님) — 원본: 이 장의 명세 버전 설명; 명령: 없음.


id: SPEC-ORDER-007
status: approved
owner: order-product
version: 3
approved_at: 2026-07-17
supersedes: SPEC-ORDER-007@2

상태는 최소한 draft, approved, superseded를 구분한다. 에이전트는 기본적으로 승인된 버전만 구현한다. 실행 시작 때 버전과 내용 해시를 input.json에 저장한다. 실행 중 명세가 바뀌면 조용히 새 내용을 섞지 않고 현재 실행을 취소하거나 새 작업으로 전환한다.

명세에서 테스트로 추적한다

수용 기준에 안정적인 식별자를 붙인다.

설계 예(실행용 아님) — 원본: 이 장의 수용 기준 설명; 명령: 없음.


- AC-01: 정상 주문은 정수형 `total`을 반환한다.
- AC-02: 취소 품목은 총액에서 제외한다.
- AC-03: 통화 누락은 `ORDER_MONEY_INVALID`를 반환한다.

테스트 이름이나 메타데이터에 ID를 연결한다.

설계 스케치(실행용 아님) — 인수 테스트 이름에 수용 기준 ID를 연결하는 모양만 보여 주며 arrange, act, assert 구현은 의도적으로 생략했다.


test("AC-02 canceled items are excluded from total", () => {
  // arrange, act, assert
});

CI는 승인된 필수 기준이 최소 하나의 실행 증거와 연결되는지 확인할 수 있다. 연결 수가 곧 품질은 아니지만, 구현됐다는 주장에 어떤 증거가 있는지 빠르게 찾게 한다.

반대 방향도 필요하다. 테스트가 더 이상 어떤 명세도 대표하지 않는다면 삭제해도 되는 회귀 방어인지, 오래된 동작을 굳힌 것인지 검토한다.

실습: 모호한 요구를 차단 가능한 명세로 바꾼다

다음 요구로 시작한다.


주문 조회에 총액을 추가한다. 기존 클라이언트가 깨지면 안 된다.

1단계: 관찰 가능한 결과

응답의 필드 이름, 타입, 단위, 존재 조건을 적는다.

2단계: 공식과 예외

품목, 할인, 배송비, 세금, 취소, 환불이 총액에 미치는 영향을 결정표로 만든다.

3단계: 호환성

기존 응답에 선택 필드를 추가하는지, 항상 존재하는 필드인지, 구버전 클라이언트가 미지 필드를 무시하는지 증거를 찾는다.

4단계: 수용 기준

정상 2개, 경계 2개, 오류 2개, 권한 1개를 AC-xx로 적는다.

5단계: 차단 질문

제품 의미에 영향을 주지만 답이 없는 항목을 open_questions에 넣는다. A/B 등급 질문이 남은 명세는 approved로 바꿀 수 없다.

6단계: 사전 검사

예제 공장의 명세 검사를 실행한다.


npm run check:specs

현재 교육용 check:specs가 실제로 확인하는 범위는 JSON 파싱, schemaVersion, 안전한 run/task ID, 중복 ID, 1~5의 시도 한도, 존재하는 의존성, 순환 의존성, 허용된 write/copy-template 연산, 작업 공간 안의 출력·템플릿·필수 파일 경로입니다. 상태, 소유자, AC, 미결정 등급은 이 장의 현장 확장 템플릿이며 현재 스크립트가 검사한다고 주장하지 않습니다.

연습으로 status/owner/acceptance/openQuestions 스키마를 추가하려면 먼저 실패 fixture와 기대 메시지를 작성합니다. 단순히 필드를 읽지 않고 A/B 미결정이 있는 승인 명세를 거부하는 테스트까지 있어야 합니다.

비기능 요구를 ‘빠르게’라고 쓰지 않는다

“빠르고 안전해야 한다”는 판정 기준이 아니다. 기준선, 관측 지점, 허용 변화, 실패 행동을 적는다.


성능: 고정된 데이터셋과 로컬 벤치마크에서 주문 100개 조회 p95가
      기준 커밋 대비 10% 넘게 악화되면 경고, 20% 넘으면 실패한다.

보안: 응답에는 저장된 결제 토큰·내부 원가가 포함되지 않는다.
      금지 필드 검사를 계약 테스트에서 실행한다.

복원력: 총액 계산 실패가 주문 목록 전체를
        부분 성공처럼 반환하지 않는다.
        정의된 오류 계약을 따른다.

작은 성능 변화는 환경 잡음일 수 있으므로 반복 횟수와 측정 환경을 함께 기록한다. 보편적 임계치라고 주장하지 않는다.

왜 실패하는가

명세가 구현 계획이 된다

파일명과 함수 호출 순서를 미리 고정하면 에이전트가 더 나은 내부 설계를 선택하지 못하고 제품 책임자가 검토하기도 어렵다. 외부 동작과 반드시 지킬 구조 제약만 명세에 둔다.

예시가 행복 경로뿐이다

모델은 빠진 예외를 합리적으로 채우려 한다. 0, 빈 값, 권한, 상태 전이, 호환성 예시를 의도적으로 추가한다.

테스트가 통과하면 명세도 맞다고 본다

테스트가 잘못된 기대를 구현할 수 있다. 독립 리뷰에서 테스트가 각 수용 기준의 의미를 올바르게 대표하는지 확인한다.

작업 중 명세를 조용히 고친다

구현자가 명세와 코드를 함께 바꾸면 판정 기준을 자신에게 맞출 수 있다. 제품 의미 변화는 별도 승인과 버전 증가를 거친다.

운영 판단: 구현을 시작해도 되는가

다음 조건이 충족되면 명세를 approved로 바꾼다.

  • 문제와 사용자 결과가 한 문단으로 설명된다.
  • 범위 안과 밖이 구분된다.
  • 핵심 용어, 공식, 상태 전이가 정의된다.
  • 정상·경계·오류·권한 예시가 있다.
  • A/B 등급 미결정이 없다.
  • 비기능 요구가 관측 가능한 기준으로 쓰였다.
  • 수용 기준 ID와 예상 증거 위치가 있다.
  • 제품 또는 도메인 소유자가 승인했다.

연습문제

  1. “검색을 더 빠르게 한다”를 측정 환경과 허용 변화가 있는 비기능 기준으로 바꿔라.
  2. 주문 할인 규칙에 대한 결정표를 만들고 빠진 조합을 두 개 찾으라.
  3. 팀의 기존 테스트 하나를 수용 기준과 연결하고, 테스트가 명세 의미를 충분히 대표하는지 비판하라.
  4. 에이전트가 선택해도 되는 C등급 결정과 사람 승인이 필요한 A등급 결정을 각각 세 개 적어라.

체크포인트

  • 주문 총액 명세에 범위, 용어, 규칙, 예시, 비기능 기준이 있다.
  • 수용 기준마다 안정적인 ID와 예상 증거가 있다.
  • A/B 등급 미결정이 있으면 공장이 시작을 거부한다.
  • 실행 입력에 명세 버전과 내용 해시가 보존된다.

다음 장에서는 승인된 명세를 한 에이전트에게 통째로 던지지 않고, 검증 가능한 작업 그래프로 나눈다.