GitHub Copilot, Claude Code, Cursor 같은 AI 코딩 도구가 코드를 생성합니다. 그만큼 개발자의 일은 명세(Specification) 작성과 검증 쪽으로 옮겨 가고 있습니다. AI에게 “무엇을 만들어”라고 말할 때와 “이 명세에 맞게 구현해”라고 말할 때 결과가 다릅니다. 이 글에서는 Spec-Driven Development(SDD)와 TDD를 결합하여 AI 코딩 에이전트를 효과적으로 다루는 방법을 소개합니다.
SDD란 무엇인가
Spec-Driven Development(SDD)는 잘 정제된 소프트웨어 명세서를 AI 코딩 에이전트의 프롬프트로 사용하여 실행 가능한 코드를 생성하는 개발 패러다임입니다. SDD에서 명세는 읽고 끝나는 문서가 아닙니다. 코드를 만들어 내는 “실행 가능한 아티팩트”로 다룹니다.
명세를 앞세우는 방식에는 긴 역사가 있습니다. 1986년 Bertrand Meyer는 Eiffel 언어에서 Design by Contract(DbC)를 주창했습니다. 이후 학계에서 TDD와 DbC를 함께 쓰는 방식이 논의됐고, Contract-First API 개발로 이어졌습니다. 2020년대에 LLM 기반 에이전트 워크플로우가 등장하면서 SDD가 다시 주목받고 있습니다.
3가지 제어 평면
SDD는 세 가지 제어 평면을 통해 AI의 코드 생성을 통제합니다.
| 제어 평면 | 역할 | 예시 |
|---|---|---|
| 선언적 의도 정의 | 무엇(What)을 할지만 정의 | API 스펙, 타입 정의, 인터페이스 |
| 결정론적 구체화 | 동일 명세에서 일관된 결과물 생성 | 코드 생성 템플릿, 제약 조건 |
| 지속적 제약 검증 | 설계 의도 이탈 방지 | 테스트, 린트 규칙, 타입 체크 |
“무엇을”은 사람이 정의하고, “어떻게”는 AI가 처리합니다. 그리고 “제대로 되었는지”는 자동화된 검증이 보장합니다.
SDD 도입의 3단계
SDD는 세 단계로 나눠 도입할 수 있습니다.
- Spec-Reference — 기존 문서를 AI에게 참고 자료로 제공합니다. API 문서, README, 아키텍처 다이어그램 등을 컨텍스트에 포함시키는 수준입니다.
- Spec-as-Prompt — 명세 자체를 프롬프트로 구조화합니다. 타입 정의, 인터페이스, 제약 조건을 명시적으로 작성하여 AI에게 전달합니다.
- Spec-as-Source — 명세가 코드의 진실의 원천(source of truth)이 됩니다. 명세가 변경되면 코드가 자동으로 재생성되고, 명세와 코드의 불일치는 CI에서 잡아냅니다.
constitution.md로 프로젝트 원칙을 정의하고, /specify로 명세를 생성하며, /plan으로 구현 계획을 수립하는 워크플로우를 제공합니다. GitHub Copilot, Claude Code, Gemini CLI 등 주요 에이전트를 모두 지원합니다.
SDD + TDD 시너지: Red-Green-Refactor 재해석
SDD의 명세는 TDD의 테스트 케이스로 바로 옮길 수 있습니다. 그래서 명세를 쓰면 TDD의 Red-Green-Refactor 사이클을 AI와 함께 돌릴 수 있습니다.
flowchart TD
subgraph Red["🔴 Red: 명세 → 테스트"]
A[명세 작성] --> B[테스트 케이스 도출]
B --> C[AI가 테스트 코드 생성]
C --> D[테스트 실패 확인]
end
subgraph Green["🟢 Green: AI 코드 생성"]
E[테스트를 AI에게 전달] --> F[AI가 구현 코드 생성]
F --> G[테스트 통과 확인]
end
subgraph Refactor["🔵 Refactor: 아키텍처 유지"]
H[AI가 리팩토링 제안] --> I[개발자가 구조 검토]
I --> J[테스트 재실행으로 검증]
end
D --> E
G --> H
J --> |다음 명세| A
Red: 명세가 곧 테스트 케이스
명세를 먼저 작성하면, 명세에서 테스트 케이스를 도출하는 일은 기계적인 작업이 됩니다. AI는 이런 변환 작업을 잘 수행합니다.
// 명세: "사용자 이메일은 반드시 유효한 형식이어야 하며,
// 도메인은 허용 목록에 포함되어야 한다"
// AI가 명세에서 도출한 테스트
describe("validateUserEmail", () => {
it("유효한 이메일 형식을 통과시킨다", () => {
expect(validateUserEmail("user@allowed.com")).toBe(true);
});
it("잘못된 이메일 형식을 거부한다", () => {
expect(validateUserEmail("not-an-email")).toBe(false);
});
it("허용 목록에 없는 도메인을 거부한다", () => {
expect(validateUserEmail("user@blocked.com")).toBe(false);
});
});
Green: AI가 테스트를 통과시킨다
실패하는 테스트가 있으면, AI 에이전트에게 “이 테스트를 통과시켜”라고 지시합니다. AI는 테스트라는 명확한 목표가 있을 때 더 정확한 코드를 생성합니다. 실패하는 테스트 하나가 모호한 자연어 지시보다 목표를 분명하게 전달합니다.
Refactor: 아키텍처 일관성 유지
AI가 생성한 코드는 동작해도 프로젝트의 아키텍처 컨벤션을 따르지 않을 수 있습니다. 이때 개발자가 구조를 검토하고 AI에게 리팩토링을 지시합니다. 테스트를 다시 실행하면 리팩토링 후에도 동작이 그대로인지 확인할 수 있습니다.
개발자 마인드셋 전환
AI 도구가 퍼지면서 개발자의 역할이 바뀌고 있습니다. 코드를 직접 작성하는 비중은 줄고, 아키텍처와 거버넌스의 비중은 늘고 있습니다.
벽돌공에서 사령관으로
과거의 개발자가 한 줄 한 줄 코드를 쌓아가는 벽돌공이었다면, AI 시대의 개발자는 전체 시스템을 조율하는 사령관에 가깝습니다.
AI가 처리하는 영역:
- 보일러플레이트 코드 생성
- CRUD 작업 구현
- 기본 테스트 케이스 생성
- 문서화
개발자가 집중해야 할 영역:
- 시스템 아키텍처 설계
- 명확한 명세 작성 (프롬프트 엔지니어링)
- AI 출력물 검증과 비판적 평가
- 표준과 정책 수립
추상화 수준의 상승
flowchart TD
subgraph 과거["과거"]
A1[요구사항] --> A2[설계]
A2 --> A3[코드 작성]
A3 --> A4[테스트]
A4 --> A5[배포]
end
subgraph 현재["AI 시대"]
B1[요구사항] --> B2[명세 작성]
B2 --> B3["AI 코드 생성"]
B3 --> B4["자동 검증"]
B4 --> B5[배포]
end
style A3 fill:#ff6b6b,color:#fff
style B2 fill:#51cf66,color:#fff
과거에는 개발자의 역량이 “코드 작성” 단계에 집중됐습니다. AI를 쓰면 그 무게가 “명세 작성” 단계로 옮겨 갑니다. 코드를 잘 짜는 능력보다 문제를 잘 정의하는 능력이 결과를 더 크게 좌우합니다.
검증 기반 신뢰
AI가 생성한 코드를 믿을지는 검증 체계로 판단합니다. 다음 세 가지를 확인합니다.
- 타입 시스템이 구조적 정합성을 보장하는가?
- 테스트가 비즈니스 로직을 커버하는가?
- CI 파이프라인이 일관성을 지키고 있는가?
이 세 가지가 갖춰져 있다면, AI가 생성했든 사람이 작성했든 코드의 품질은 동일하게 보장됩니다.
실전 적용 가이드
SDD + TDD를 실무에 적용하는 구체적인 워크플로우를 살펴봅니다.
워크플로우 예시
하나의 기능을 구현할 때의 흐름입니다.
1단계: 명세 작성
## 기능: 사용자 프로필 이미지 업로드
### 제약 조건
- 허용 형식: JPEG, PNG, WebP
- 최대 파일 크기: 5MB
- 업로드 후 256x256 리사이즈
- S3에 저장, CDN URL 반환
### 인터페이스
- POST /api/users/:id/avatar
- Request: multipart/form-data (file)
- Response: { url: string, updatedAt: string }
### 에러 케이스
- 415: 지원하지 않는 파일 형식
- 413: 파일 크기 초과
- 404: 존재하지 않는 사용자
2단계: 명세 → 테스트 (AI 활용)
명세를 AI에게 전달하여 테스트 케이스를 생성합니다. 생성된 테스트를 검토하여 누락된 엣지 케이스를 보완합니다.
3단계: 테스트 → 구현 (AI 활용)
실패하는 테스트를 AI에게 전달하여 구현 코드를 생성합니다. 테스트가 모두 통과하는지 확인합니다.
4단계: 리팩토링 (개발자 + AI)
프로젝트 컨벤션에 맞게 코드 구조를 정리합니다. 테스트 재실행으로 안전성을 확인합니다.
도구별 활용 팁
| 도구 | 특징 | SDD+TDD 활용법 |
|---|---|---|
| GitHub Copilot | 테스트-코드 순환 최적화 | Spec Kit과 함께 사용, 테스트에서 구현 자동 생성 |
| Claude Code | 컨텍스트 이해와 계획 수립 | 명세를 CLAUDE.md에 포함, TDD 사이클 전체 관리 |
| Cursor | 빠른 편집과 자동완성 | 인라인 명세 주석으로 가이드, 짧은 반복 사이클 |
인지 위축에 대한 경고
AI 도구에 많이 의존할수록 인지 위축(Cognitive Atrophy) 위험이 커집니다.
AI가 코드를 대신 짜주니 직접 코딩하는 빈도가 줄어듭니다. 코딩 빈도가 줄면 문제 해결 능력과 디버깅 감각이 둔해집니다. 내비게이션에 의존하면 길을 찾는 감각이 무뎌지는 것과 같은 원리입니다.
SDD + TDD는 이 위험을 줄입니다.
- 명세 작성은 문제를 깊이 이해해야만 가능합니다
- 테스트 설계는 엣지 케이스를 직접 사고해야 합니다
- 코드 리뷰는 AI 출력물을 비판적으로 평가하는 훈련이 됩니다
“사령관”이라도 전장의 기본 원리를 모르면 잘못된 명령을 내립니다. AI를 쓰더라도 기본 역량은 직접 연습해 유지합니다.
마무리
SDD는 명세로 AI에게 무엇을 만들지 알려 주고, TDD는 테스트로 결과물이 명세대로 동작하는지 확인합니다. 두 방법을 함께 쓰면 AI 코딩 에이전트의 결과를 예측하고 검증할 수 있습니다.
다음에 AI에게 코드를 요청할 때는 자연어 지시 대신 명세를 먼저 작성하고, 그 명세로 테스트를 먼저 만들어 보세요.