요구사항부터 코드까지: 스펙 기반 개발 워크플로

의도부터 검증된 코드까지의 5단계

Page content

규격 기반 개발(Spec-Driven Development)은 규격이 문서화되어 서랍에 넣어지는 것이 아니라, 워크플로우로 기능할 때 비로소 효과를 발휘합니다. 핵심은 방대한 제품 요구사항 문서를 작성하는 것이 아닙니다.

핵심은 프로덕션 코드를 변경하기 전에 — 인간이든 AI 에이전트든 — 모호함을 줄여주는 일련의 검토 가능한 산출물(artifacts)을 순차적으로 통과하는 것입니다.

SDD의 개념적 정의를 아직 알지 못하신다면, What Is Spec-Driven Development? 문서를 참고하시기 바랍니다. 해당 문서에는 정의, TDD 및 BDD와의 비교, 그리고 규격을 진실의 원천(source of truth)으로 대해야 하는 이유에 대한 논증이 포함되어 있습니다. 본 문서는 App Architecture 문서 클러스터에 포함된 운영 가이드입니다. 이 글에서는 5개 단계를 순서대로 살펴보고, 각 단계의 산출물에 무엇이 포함되어야 하는지, AI 에이전트가 어디에 위치하는지 설명하며, 오늘 바로 리포지토리에 복사해서 사용할 수 있는 재사용 가능한 템플릿을 제공합니다.

Spec-driven development workflow – requirements, design, tasks, implementation, validation

SDD는 문서가 아닌 워크플로우입니다

규격 기반 개발에서 가장 흔한 실패 유형은 규격을 단순한 서류 작업으로 취급하는 것입니다. 팀이 긴 요구사항 문서를 작성하고 위키에 저장한 뒤, 기억과 채팅 스레드를 바탕으로 코딩을 시작합니다. 규격은 존재하지만 아무것도 주도하지 않습니다. 이는 ‘문서화 극(documentation theater)‘에 해당하며, 규격이 없는 것보다 더 나쁩니다. 왜냐하면 이는 잘못된 자신감을 주기 때문입니다.

효과적인 SDD 워크플로우는 각 단계가 시작되기 전에 검토되는 산출물의 연쇄를 생성합니다. 요구사항은 제품 관련 모호함을 줄이고, 설계는 기술적 모호함을 줄이며, 태스크는 실행 관련 모호함을 줄입니다. 구현은 알려진 목표에 맞춰 코드를 생성하고, 검증은 그 연쇄가 유지되었음을 증명합니다. 어느 단계에서든 실수가 발견되면, 해당 산출물을 수정하고 그 지점부터 다시 실행해야 합니다. 3,000줄의 오차가 main 브랜치에 합쳐진 뒤에 수정해서는 안 됩니다.

flowchart LR A[Specify] --> B[Plan] B --> C[Tasks] C --> D[Implement] D --> E[Validate] E -->|drift found| A E -->|ship| F[Done]

이 워크플로우는 도구 중립적(tool-neutral)입니다. Git의 마크다운 파일로, GitHub Spec Kit로, Cursor 플랜으로, Superpowers와 같은 강제된 스킬 패키지로, 또는 단순한 텍스트 에디터와 엄격한 리뷰어로 실행할 수 있습니다. 중요한 것은 도구의 브랜드가 아니라, 순서와 검토 게이트입니다.

Phase 1 – 요구사항 명세(Specify the Requirements)

명세(Specify) 단계는 어떤 문제를 해결하는지, 그리고 ‘완료’가 어떤 모습인지에 대한 답을 제시합니다. 이 단계는 의도적으로 ‘어떻게 구축할 것인가’를 회피합니다. 요구사항 명세에 “Redis 정렬 집합을 사용하라"고 적는 순간, 당신은 명세 작성을 중단하고 잘못된 문서에서 설계를 시작하게 된 것입니다. 구현 내용을 요구사항에서 제외하십시오. 그것은 플랜(Plan)에 넣어야 합니다.

문제 진술과 사용자

평이한 언어로 문제를 서술하는 한 단락으로 시작하십시오. 영향을 받는 사용자를 명시하고, 그 문제를 고통스럽게 만드는 상황을 설명하십시오. 좋은 문제 진술은 기획 회의에 참석하지 않은 리뷰어가 제안된 솔루션이 실제로 그 고통을 해결하는지 판단할 수 있게 해줍니다.

API 레이트 리미팅 기능에 대한 예시:

무료 티어의 API 소비자는 무제한으로 요청을 보낼 수 있으며, 이는 비용 급증과 유료 테넌트에 대한 노이시 네이버(noisy-neighbor) 영향을 초래합니다. 플랫폼 운영자는 수동 개입 없이 강제 가능한 키별 제한이 필요합니다.

목표, 비목표, 수용 기준

목표(Goals)는 전달할 결과물을 설명합니다. 비목표(Non-goals)는 유혹적인 인접 작업 중 의도적으로 하지 않을 부분을 명시합니다. 이 둘은 에이전트의 창의성을 제한하며, 이는 AI 도구가 “도움"을 준다는 명목으로 범위를 확장하는 것을 방지하는 데 필수적입니다.

섹션 좋은 예시 약한 예시
목표 키별 제한을 초과하는 요청을 HTTP 429로 거부 API를 더 빠르게 만들기
비목표 테넌트별 과금 대시보드 모든 API 성능 개선
수용 기준 인증되지 않은 요청은 레이트 체크 실행 전 401을 수신 엔드포인트가 안전하다

수용 기준은 각 기준이 최소 하나의 테스트에 매핑될 만큼 정확해야 합니다. “엔드포인트가 안전하다"는 수용 기준이 아닙니다. “인증되지 않은 요청은 HTTP 401을 수신한다"가 수용 기준입니다. 구체적인 기준을 작성할 수 없다면, 그 요구사항은 구현하기에 여전히 모호합니다.

미해결 질문

아직 결정되지 않은 모든 결정을 나열하십시오. 불분명한 질문은 실패의 징후가 아닙니다. 그것은 명세 단계가 제 역할을 하고 있다는 의미입니다. 설계 플랜을 작성하기 전에 이를 해결하십시오. 그렇지 않으면 구현 단계에서 재작업으로 인해 그 모호함의 대가를 치르게 됩니다.

최소 요구사항 템플릿:

## Problem
[One paragraph: who hurts, why, and what triggers the pain.]

## Users
- [Primary user role]
- [Secondary user role]

## Goals
1. [Measurable outcome]
2. [Measurable outcome]

## Non-goals
- [Explicitly out of scope]
- [Explicitly out of scope]

## Acceptance criteria
- [ ] [Verifiable behavior]
- [ ] [Verifiable behavior]

## Open questions
- [ ] [Question that blocks planning]

Phase 2 – 설계 플랜 수립(Plan the Design)

플랜 단계는 의도(Intent)를 기술적 결정으로 번역합니다. 여기에는 Redis 정렬 집합 사용, 모듈 경계, 스키마 변경, API 계약, 마이그레이션 단계, 보안 제약, 테스트 전략 등이 포함됩니다. 플랜은 요구사항 명세와 프로젝트의 기존 제약 조건(스택 선택, decision records, AGENTS.md나 프로젝트 헌장에 저장된 관행 등)을 기반으로 도출됩니다.

아키텍처와 영향받는 모듈

변경될 모듈, 서비스, 또는 패키지를 명시하고 통합 패턴을 요약하십시오. 기능이 서비스 경계를 넘나든다면, 양쪽의 계약을 문서화하십시오. 계약이 암묵적일 때 에이전트는 API를 환각(hallucinate)하기 쉽습니다. 플랜에서 이를 명시적으로 만드는 것은 발명된 엔드포인트와 잘못된 응답 형식을 방지합니다.

데이터 모델, API 계약, 마이그레이션

스키마 변경, 새로운 테이블이나 필드, 인덱스 요구사항, 그리고 후방 호환성 규칙을 문서화하십시오. HTTP API의 경우, 메서드, 경로, 요청 형상, 응답 형상, 에러 코드를 기록하십시오. 이벤트의 경우, 토픽 이름, 페이로드 스키마, 전달 의미를 기록하십시오. 데이터 모델이 변경되면 마이그레이션 단계와 롤백 노트를 포함하십시오.

보안, 관찰 가능성, 테스트 전략

보안 제약은 코드 리뷰에서의 사후 고려사항이 아니라, 플랜에 포함되어야 합니다. 인증 요구사항, 인가 규칙, 입력 검증 경계, 그리고 로그에 나타나면 안 되는 데이터를 명시하십시오. 관찰 가능성(Observability)은 기능이 프로덕션에서 정상 작동하는지 확인하는 데 필요한 지표, 로그, 또는 트레이스를 커버해야 합니다.

테스트 전략은 수용 기준과 연결되어야 합니다. 어떤 기준은 단위 테스트가, 어떤 기준은 통합 테스트가, 어떤 기준은 수동 검증이 필요한지 식별하십시오. Go에서의 단위 테스트Python에서의 단위 테스트를 사용한다면, 추가할 패키지 및 테스트 파일을 명시하십시오. 테스트 전략이 없는 플랜은 프로덕션에서 발견하게 될 결함들을 그대로 출시하게 되는 플랜입니다.

flowchart TB subgraph plan [Design plan contents] R[Requirements spec] C[Project constitution / ADRs] R --> D[Architecture decisions] C --> D D --> M[Data model and migrations] D --> A[API contracts] D --> S[Security constraints] D --> T[Test strategy] end

Phase 3 – 구현 태스크 분해(Break Down Implementation Tasks)

태스크 단계는 플랜을 독립적으로 구현, 검토, 검증할 수 있을 만큼 작은 조각으로 분해합니다. 이것이 에이전트 지원 개발을 검토 가능하게 만드는 핵심입니다. 거대한 단일 디프(diff) 대신, 각 태스크가 명명된 요구사항과 매핑되는 집중적인 변경 사항의 순서를 얻게 됩니다.

태스크 크기 및 의존성

좋은 태스크는 제한된 파일 집합을 다루고, 하나의 에이전트 세션에서 완료되며, 검증 단계로 끝납니다. 태스크는 의존성을 명시적으로 선언해야 합니다. 마이그레이션 태스크는 새 스키마를 읽는 코드보다 먼저 실행되어야 합니다. 공용 라이브러리 변경은 소비자(consumer)보다 먼저 실행되어야 합니다. 인증 미들웨어 변경은 새 동작에 의존하는 엔드포인트보다 먼저 실행되어야 합니다.

flowchart TD T1[Task 1 -- schema migration] --> T2[Task 2 -- repository layer] T2 --> T3[Task 3 -- HTTP handler] T2 --> T4[Task 4 -- metrics instrumentation] T3 --> T5[Task 5 -- integration tests] T4 --> T5

파일, 검증, 검토 체크포인트

각 태스크는 변경될 가능성이 있는 파일, 충족하는 수용 기준, 완료 검증 방법을 나열해야 합니다. 검증은 테스트 명령, curl 예시, 또는 복사-붙여넣기 가능한 단계로 설명된 수동 확인일 수 있습니다. 모든 태스크는 인간 리뷰 체크포인트에서 끝납니다. 리뷰어는 다음 태스크가 시작되기 전에 디프가 태스크 설명과 일치하는지 확인합니다.

최소 태스크 항목:

### Task 3 -- Add rate-limit middleware

**Depends on:** Task 1 (schema), Task 2 (repository)
**Files:** middleware/ratelimit.go, middleware/ratelimit_test.go, server.go
**Satisfies:** AC-2 (429 over limit), AC-3 (limit headers in response)
**Validate:** `go test ./middleware/...` passes; curl over limit returns 429 with Retry-After
**Review checkpoint:** Confirm middleware runs after auth, before handler

생성된 태스크 폭발에 주의하십시오. AI 에이전트는 몇 초 만에 50개 태스크의 플랜을 생성할 수 있습니다. 그 중 대부분은 중복적이거나 효율적인 검토에 너무 세분화되어 있을 것입니다. 중간 규모 기능에 유용한 태스크 목록은 보통 50개가 아닌 5개에서 15개 항목입니다.

Phase 4 – 한 번에 하나의 태스크 구현(Implement One Task at a Time)

구현은 의도적으로 좁게 설정됩니다. 하나의 태스크를 선택하고, 에이전트에게 해당 태스크에 필요한 컨텍스트만 제공한 후, 검증이 통과하면 중단하십시오. 태스크 간의 컨텍스트 리셋은 버그가 아닌 기능입니다. 이는 이전 가정이 후속 작업을 오염시키는 것을 방지하고 디프를 검토 가능하게 유지합니다.

규격 스택으로부터 제약 조건 적용

구현 에이전트는 요구사항 명세, 설계 플랜, 현재 태스크 설명, 프로젝트 레벨 제약 조건을 읽어야 합니다. 제약 조건은 대부분의 팀이 건너뛰는 가장 높은 ROI(투자 대비 수익) 섹션입니다. 이는 에이전트에게 무엇을 하지 말아야 하는지 알려줍니다 — 관련 없는 모듈을 리팩토링하지 말 것, 이 기능 밖의 공개 API 서명을 변경하지 말 것, 플랜을 업데이트하지 않고 새로운 의존성을 도입하지 말 것.

현실이 다를 때 플랜 업데이트

구현 과정에서 예상치 못한 상황이 드러납니다. 라이브러리가 가정된 동작을 지원하지 않을 수 있고, 마이그레이션이 예상보다 오래 걸릴 수 있으며, 수용 기준에서 엣지 케이스가 누락되었을 수 있습니다. 이런 일이 발생하면 계속 진행하기 전에 규격을 업데이트하십시오. 요구사항이나 플랜을 수정하고, 빠른 검증을 거친 후, 수정된 산출물에 맞춰 구현을 재개하십시오. 규격과 조용히 이탈하는 코드는 드리프트(오차)가 영구화되는 방식입니다.

sequenceDiagram participant H as Human reviewer participant A as AI agent participant S as Spec artifacts H->>S: Approve task N A->>S: Read task + plan + constraints A->>A: Implement task N A->>A: Run task validation A->>H: Submit diff for review H->>H: Review diff against task alt drift or surprise H->>S: Update spec/plan H->>A: Re-run with corrected context else approved H->>S: Mark task N complete H->>A: Proceed to task N+1 end

Phase 5 – 규격에 대한 검증(Validate Against the Spec)

검증은 SDD가 그 가치를 입증하는 곳입니다. 없다면, 규격은 단순한 기획 연습에 불과합니다. 있다면, 규격은 출시된 코드와 대조할 수 있는 계약이 됩니다.

자동화 체크

CI에서 전체 테스트 스위트, 린트, 타입 체크를 실행하십시오. 실용적인 시작점이 필요하시다면 GitHub Actions cheatsheet의 패턴을 사용하여 파이프라인에 연결하십시오. 자동화 체크는 회귀를 포착합니다. 그러나 올바르게 구축된 잘못된 기능은 포착하지 못하므로, 수용 기준 리뷰는 여전히 중요합니다.

수용 기준 및 수동 리뷰

요구사항 명세의 각 수용 기준을 하나씩 검토하십시오. 각 기준을 충족, 실패, 또는 정당한 이유를 들어 지연으로 표시하십시오. 수동 리뷰는 UX 문제, 보안 결함, 그리고 규격이 결함이 있었기에 테스트에 맞춰 작성된 결과 놓친 잘못된 동작을 포착합니다.

규격-코드 디프

최종 검증 단계는 구현을 설계 플랜과 비교합니다. 변경된 파일이 플랜이 예측한 파일과 일치했습니까? 코드 내 아키텍처 결정이 기록된 결정과 일치했습니까? 디프 내의 예상치 못한 파일은 신호입니다 — 플랜이 불완전했거나 에이전트가 이탈한 것일 수 있습니다. 둘 다 머지 전에 주의를 기울여야 합니다. Keeping Specs, Tests, And Code In Sync In AI Development는 이 일회성 디프 리뷰를 반복 가능한 추적 테이블과 CI 체크 세트로 전환하여, 누군가 확인해야 할 때만이 아니라 모든 PR에서 드리프트가 포착되도록 합니다.

검증 계층 포착 대상
단위 및 통합 테스트 범위 내 회귀 및 잘못된 로직
린트 및 타입 체크 스타일 문제 및 타입 에러
수용 기준 워크스루 규격에 맞춰 구축된 잘못된 동작
규격-코드 디프 아키텍처 드리프트 및 범위 크리프

워크플로우에서 AI 에이전트의 역할

AI 에이전트는 각 단계의 가속기이지, 리뷰의 대체재가 아닙니다. 생산적인 패턴은 초안 작성, 리뷰, 개선, 그리고 진행입니다. 문제 설명으로부터 요구사항 명세의 초안을 작성하도록 에이전트에게 요청한 후, 목표, 비목표, 수용 기준이 정확해질 때까지 의도를 편집하십시오. 승인된 요구사항으로부터 설계 플랜의 초안을 작성하도록 요청한 후, 코드가 존재하기 전에 아키텍처 결정을 검토하십시오. 에이전트에게 한 번에 하나의 태스크 조각을 구현하도록 요청하고, 다음 태스크가 시작되기 전에 각 디프를 승인하십시오.

flowchart LR subgraph human [Human owns] H1[Intent and priorities] H2[Architecture approval] H3[Diff review at checkpoints] H4[Final acceptance] end subgraph agent [Agent accelerates] A1[Draft requirements] A2[Draft design plan] A3[Generate task list] A4[Implement task slices] A5[Draft tests] end H1 --> A1 --> H1 A1 --> A2 --> H2 H2 --> A3 --> A4 --> H3 H3 --> A4 A4 --> A5 --> H4

에이전트는 첫 번째 초안과 보일러플레이트 테스트 생성에 특히 유용합니다. 인간은 잘못된 목표, 안전하지 않은 아키텍처, 미묘한 범위 크리프를 포착하는 데 특히 유용합니다. 워크플로우는 어느 한쪽이 건너뛰어지면 실패합니다 — 규격 없이 에이전트가 구현하거나, 인간이 규격을 작성하지만 코드와 대조하여 검증하지 않는 경우.

이 워크플로우 문서는 의도적으로 도구 중립적입니다. 도구별 실행 가이드(에디터 설정, 슬래시 커맨드, 에이전트 구성)는 AI Developer Tools 클러스터 아래에 속합니다. 프로세스의 뿌리는 산출물이 벤더보다 중요하기 때문에 문서화 관행 아래 여기에서 다뤄집니다.

규격 기반 개발을 무너뜨리는 흔한 실수

검증 전의 거대한 규격. 프로토타입이나 스파이크(spike) 전에 작성된 30페이지 분량의 요구사항 문서는 SDD가 아니라 워터폴 서류 작업입니다. 다음 단계의 모호함을 제거하는 최소한의 규격을 작성하고, 가정을 조기 검증하십시오. 모든 기능이 5단계 루프 전체가 필요한 것은 아닙니다 – Spec-Driven Development vs Vibe Coding은 가벼운 구조가 충분한 시점을 설명합니다.

모호한 수용 기준. “빠른”, “깔끔한”, “사용자 친화적인"과 같은 형용사는 수용 기준이 아닙니다. 이를 측정 가능한 동작으로 대체하십시오. 테스트할 수 없다면, 신뢰할 수 있게 구현할 수 없습니다 — 특히 AI 에이전트를 사용할 때.

비목표 누락. 비목표가 없으면, 에이전트는 기본적으로 범위를 확장합니다. 캐싱 레이어를 추가하고, 인접 모듈을 리팩토링하며, 요청하지 않은 의존성을 도입합니다. 비목표는 사전에 ‘아니오’라고 말하는 방법입니다.

설계 단계의 테스트 플랜 부재. 구현 후에만 작성된 테스트는 의도한 것이 아니라 구축된 것을 확인하는 경향이 있습니다. 플랜은 첫 번째 프로덕션 파일이 변경되기 전에, 어떤 수용 기준이 어떤 테스트 유형에 매핑되는지 명시해야 합니다.

단계 경계에서의 리뷰 생략. 플랜 전에 규격이 검토되어야 하고, 태스크 전에 플랜이 검토되어야 하며, 구현 전에 태스크가 검토되어야 합니다. 각 게이트는 저렴합니다. 대형 머지 이후 드리프트를 수정하는 것은 비용이 많이 듭니다.

생성된 태스크 폭발 방치. AI가 생성한 50개 항목의 태스크 목록을 일정표가 아닌 첫 번째 초안으로 취급하십시오. 중복 항목을 병합하고, 과도하게 큰 항목을 분할하며, 요구사항에 매핑되지 않는 태스크는 삭제하십시오.

SDD는 각 단계가 모호함을 줄일 때 작동합니다. 서류 작업을 생성할 때 실패합니다.

재사용 가능한 템플릿

이것들을 리포지토리에 복사하고 적응시키십시오. 규격을 기능 브랜치와 함께 저장하고, 풀 리퀘스트에서 검토하며, 에이전트와 인간이 동일한 소스를 읽도록 버전 관리에 유지하십시오.

요구사항 템플릿

# Feature -- [name]

## Problem
## Users
## Goals
## Non-goals
## Acceptance criteria
## Open questions

설계 템플릿

# Design -- [feature name]

## Summary
## Affected modules
## Data model changes
## API contracts
## Migrations
## Security
## Observability
## Test strategy
## Risks and mitigations

태스크 목록 템플릿

# Tasks -- [feature name]

## Task 1 -- [title]
Depends on:
Files:
Satisfies:
Validate:
Review checkpoint:

## Task 2 -- [title]
...

검증 체크리스트

# Validation -- [feature name]

## Automated
- [ ] All tests pass
- [ ] Lint clean
- [ ] Type check clean

## Acceptance criteria
- [ ] AC-1 --
- [ ] AC-2 --

## Spec-to-code
- [ ] Changed files match plan
- [ ] No undocumented architectural changes
- [ ] Spec updated if implementation differed

결론

규격 기반 개발은 더 많은 문서를 작성하는 것에 관한 것이 아닙니다. 이것은 명세, 플랜, 태스크, 구현, 검증 단계를 거치며 각 단계마다 검토 게이트를 두는 것에 관한 것입니다. 각 단계는 다음 행위자(인간 또는 에이전트)에게 이전 단계보다 더 적은 추측을 남겨야 합니다.

작게 시작하십시오. 중간 규모의 기능 하나에 전체 워크플로우를 실행하십시오. 산출물을 마크다운으로 리포지토리에 유지하십시오. 현실이 이탈할 때 규격을 업데이트하십시오. 머지 전에 검증하십시오. 연쇄가 작동하면, 더 적은 드리프트, 더 작고 검토 가능한 디프, 그리고 세션 리셋과 팀 인계에서도 살아남는 지속 가능한 의도의 기록을 얻게 됩니다.

연쇄가 서류 작업이 되면, 범위를 줄이십시오 — 리뷰를 줄이는 것이 아닙니다. 검증된 2페이지 규격이 아무도 읽지 않은 30페이지 규격보다 낫습니다.

유용한 링크

구독하기

시스템, 인프라, AI 엔지니어링에 관한 새 글을 받아보세요.