[Spec Kit ⑦] 실전 — 데이터 품질 모니터링 서비스를 SDD로 만들기 (회고)
constitution부터 converge까지, 실시간 데이터 품질 모니터링 서비스(dq-monitor)를 SDD로 0에서 1까지 만든 엔드투엔드 케이스 스터디입니다. 정직한 숫자, 우리가 밟은 함정, 그리고 SDD를 켜고 끄는 판단까지 — 7부작 시리즈를 닫습니다.
여섯 편 동안 우리는 개념(1부)에서 출발해 도구를 깔고(2부), 헌법을 세우고(3부), 명세와 명료화(4부), 계획과 작업 분해(5부), 구현과 수렴(6부)까지 한 걸음씩 걸어왔습니다. 그런데 단계를 하나씩 분리해 설명하면, 정작 가장 궁금한 질문이 답을 못 얻습니다. "그래서 빈 저장소에서 동작하는 서비스까지, 전체를 통으로 돌리면 어떤 느낌인가? 시간은 어디에 쓰이고, 무엇이 손해고 무엇이 이득이며, 어디서 넘어졌나?" 이 마지막 글은 그 통합 회고입니다. 우리가 시리즈 내내 만들어 온 실시간 데이터 품질 모니터링 서비스 dq-monitor를 SDD로 0→1까지 만든 여정을, 미화 없이 정직하게 되짚습니다.
이 글에서 배우는 것
- constitution → converge 전 단계가
dq-monitor에서 어떤 구체 산출물을 만들어 냈는지 한눈에 매핑- "스펙·명료화 vs 구현"에 시간이 어떻게 갈렸는지, 선불로 낸 명세 비용이 나중에 무엇을 사 줬는지 (정직한 숫자)
- 우리가 실제로 밟은 함정 5가지와 그 교정법 — 이 글에서 가장 값진 부분
- SDD를 켜야 할 때와 과한 때를 가르는 결정 테이블
- 다음 기능에 이번 주 바로 적용할 수 있는 도입 체크리스트
이 글은 Spec Kit 시리즈의 7부이자 마지막입니다. 앞선 여섯 편을 읽지 않았더라도 회고 자체는 따라올 수 있도록 썼지만, 각 단계의 디테일은 해당 부를 함께 보시길 권합니다.
들어가기 전에: 이 글의 시간·비율·횟수 같은 수치는 한 차례 실제 작업을 바탕으로 정리·예시화한 값입니다. 절대 벤치마크가 아니라, "이런 결의 분포"를 보여 주는 참고치로 읽어 주세요. 여러분의 팀·도메인·모델 버전에 따라 숫자는 얼마든지 달라집니다.
1. 전체 여정을 한 장에
먼저 큰 그림입니다. SDD 워크플로의 각 단계가 dq-monitor에서 무엇을 만들어 냈고, 그 단계를 시리즈의 어느 부에서 다뤘는지 한 표로 모았습니다. 이 표 하나가 사실상 시리즈 전체의 목차이자 이 회고의 뼈대입니다.
| 단계 | 명령 | 한 줄 의미 | dq-monitor에서 나온 산출물 | 다룬 부 |
|---|---|---|---|---|
| 헌법 | /speckit.constitution | 프로젝트를 관통하는 원칙 | .specify/memory/constitution.md — 데이터 정확성·관측가능성·테스트·성능 원칙 | 3부 |
| 명세 | /speckit.specify | 무엇·왜 (요구사항·유저 스토리) | specs/001-dq-monitor/spec.md — 신선도·정합성·이상치 감시 + 알림 | 4부 |
| 명료화 | /speckit.clarify | 순차 질문으로 빈틈 메우기 | specs/001-dq-monitor/clarifications.md — 임계값·중복알림·SLA 결정 | 4부 |
| 계획 | /speckit.plan | 어떻게 (기술 설계·아키텍처) | plan.md + data-model.md + contracts/ + research.md | 5부 |
| 작업 | /speckit.tasks | 의존성 순서가 있는 작업 분해 | tasks.md — T001~T0NN, 순서·병렬표시 | 5부 |
| 분석 | /speckit.analyze | spec·plan·tasks 교차검증 | 정합성 리포트 — 누락·모순 목록과 수정 | 5부 |
| 구현 | /speckit.implement | 작업을 실행해 코드 생성 | 실제 dq-monitor 코드베이스 | 6부 |
| 수렴 | /speckit.converge | 코드 vs 산출물 대조·잔여 회수 | 보강된 tasks.md + 완료 검증 | 6부 |
핵심은, 이 산출물들이 전부 저장소 안의 평문 텍스트 파일이라는 점입니다(1부에서 강조한 "에이전트 잠금 없음"의 실체). dq-monitor를 Claude Code로 만들었지만, 같은 specs/001-dq-monitor/ 폴더를 들고 다른 에이전트로 옮겨도 자산은 그대로 살아 있습니다.
2. 빈 저장소에서 동작하는 서비스까지 — 압축 워크스루
이제 같은 여정을 시간순으로, 각 /speckit.*이 실제로 무엇을 뱉어 냈는지 짧은 발췌와 함께 따라갑니다. 전체 파일을 다시 붙이지는 않습니다(그건 4~6부의 몫입니다). 여기서는 "이 단계가 끝났을 때 손에 뭐가 남았나"만 봅니다.
2.1 git init 다음 줄 — /speckit.constitution
빈 저장소에서 가장 먼저 한 일은 코드가 아니라 원칙이었습니다. dq-monitor는 데이터를 다루는 서비스이므로, 헌법의 첫 조항은 "데이터 정확성이 가용성보다 우선한다"였습니다. 즉 의심스러운 데이터는 통과시키느니 막고 알린다.
# dq-monitor Constitution (발췌)
## 원칙 1. 데이터 정확성 우선
- 불확실한 검사 결과는 PASS가 아니라 UNKNOWN으로 표기한다.
## 원칙 2. 관측가능성
- 모든 검사 실행은 구조화 로그 + 메트릭으로 남긴다.
## 원칙 3. 테스트
- 모든 검사 규칙(rule)은 정상/이상 픽스처를 동반한다.
## 원칙 4. 성능
- 단일 검사 배치는 데이터셋 1천만 행 기준 5분 내.이 네 줄짜리 원칙이 나중에 계획과 구현 단계에서 반복적으로 인용됩니다. "성능 5분"은 plan에서 배치 아키텍처 선택의 근거가 되고, "UNKNOWN 표기"는 data-model의 상태 enum에 그대로 박힙니다.
2.2 무엇·왜 — /speckit.specify
다음은 기술을 한 줄도 적지 않고 무엇을, 왜 만드는지였습니다. 핵심 유저 스토리는 셋이었습니다.
| ID | 유저 스토리 (요약) |
|---|---|
| US-1 | 데이터 엔지니어로서, 테이블 신선도가 SLA를 넘기면 알림을 받아 파이프라인 지연을 즉시 안다 |
| US-2 | 데이터 엔지니어로서, 핵심 컬럼의 null·유니크·범위 규칙 위반을 감지해 다운스트림 오염을 막는다 |
| US-3 | 분석가로서, 일일 행 수의 통계적 이상치를 감지해 적재 누락/중복을 조기에 잡는다 |
이 단계의 산출물 spec.md에는 의도적으로 "Postgres"도 "Kafka"도 없습니다. 무엇(신선도·정합성·이상치 감시 + 알림)과 왜(다운스트림 오염 방지)만 있습니다. 기술 선택은 다음 단계의 몫입니다.
2.3 빈틈 메우기 — /speckit.clarify
specify가 끝나자마자 clarify를 돌렸더니, 명세가 조용히 비워 두고 있던 결정들이 질문으로 튀어나왔습니다. 순차 질문에 답하며 메운 빈틈의 일부입니다.
- 신선도 임계값은 누가 정하나? → 테이블별 설정(YAML), 미설정 시 24시간 기본값.
- 같은 위반이 반복되면 매번 알림? → 아니오. 동일 (검사, 대상) 키로 60분 디듀프, 해소 시 1회 복구 알림.
- "이상치"의 정의는? → 28일 윈도우 기준 평균±3σ 이탈, 최소 14일 데이터 누적 전엔 판정 보류(UNKNOWN).
이 세 줄이 없었다면 구현 단계의 AI는 "그럴듯하게" 임계값을 하드코딩하고, 알림을 매분 쏘고, 데이터 2일 치로 이상치를 단정했을 겁니다. clarify는 AI의 자유도를 줄이는 게 아니라, 사람이 책임질 결정을 사람에게 되돌려주는 단계였습니다.
2.4 어떻게 — /speckit.plan
이제 비로소 기술이 등장합니다. plan은 헌법과 명세를 입력으로 받아 아키텍처를 설계했고, 한 파일이 아니라 여러 산출물로 나왔습니다.
| 산출물 | 내용 (발췌) |
|---|---|
plan.md | 스케줄러 → 검사 워커 → 결과 저장 → 알림 디스패처. Python + APScheduler, 결과는 Postgres. |
data-model.md | Check, CheckRun(status: PASS/FAIL/UNKNOWN), Incident, Notification 엔티티 |
contracts/ | 검사 규칙 플러그인 인터페이스, 알림 채널 인터페이스(Slack/Webhook) |
research.md | "왜 APScheduler인가" 등 기술 선택의 근거와 대안 비교 |
여기서 헌법이 일을 합니다. CheckRun.status에 UNKNOWN이 있는 건 우연이 아니라 원칙 1을 데이터 모델로 번역한 결과입니다.
2.5 작업으로 쪼개기 — /speckit.tasks
tasks는 계획을 의존성 순서가 있는 체크 가능한 작업 목록으로 분해했습니다.
# tasks.md (발췌)
- [ ] T001 프로젝트 스캐폴딩 / 의존성 / lint·test 설정
- [ ] T002 [P] data-model 엔티티 + 마이그레이션
- [ ] T003 [P] 검사 규칙 플러그인 인터페이스 (contracts 기반)
- [ ] T004 신선도 검사 규칙 + 픽스처 (US-1)
- [ ] T005 정합성 검사 규칙(null/unique/range) + 픽스처 (US-2)
- [ ] T006 이상치 검사 규칙(28일/3σ) + 픽스처 (US-3)
- [ ] T007 알림 디스패처 + 60분 디듀프
- [ ] T008 스케줄러 통합 + 엔드투엔드 스모크 테스트[P]는 병렬 가능 표시이고, 각 작업이 어떤 유저 스토리(US-n)를 만족하는지 추적됩니다. 이 추적성 덕분에 나중에 "이 코드 왜 있지?"가 "T005 → US-2"로 즉시 답이 됩니다.
2.6 합치기 전 검문 — /speckit.analyze
구현에 들어가기 직전, analyze로 spec·plan·tasks 셋을 교차검증했습니다. 실제로 잡힌 것:
- 명세의 US-3(이상치)은 "최소 14일 누적 전 판정 보류"를 요구했는데,
tasks.md의 T006엔 그 보류 로직이 빠져 있었습니다. → T006을 쪼개 "콜드스타트 가드" 하위 작업을 추가. plan은 Slack·Webhook 두 채널을 말했는데tasks엔 Webhook 작업이 없었습니다. → T007에 채널 추상화 명시.
이 두 개가 analyze의 본전입니다. 구현이 다 끝난 뒤 발견했다면 재작업이었을 결함을, 코드 한 줄 쓰기 전에 명세 수정으로 막았습니다.
2.7 실제 코드 — /speckit.implement
여기서 처음으로 진짜 코드가 나옵니다. implement는 tasks.md를 위에서부터 순서대로 실행했습니다. 중요한 건, 이 단계가 "한 방에 다 짜 줘"가 아니라 작업 단위로 끊어서 진행됐다는 점입니다. T002가 끝나면 마이그레이션이 돌아가고, T004가 끝나면 신선도 검사 픽스처 테스트가 초록불이 됩니다. 각 작업이 헌법 원칙 3("모든 규칙은 픽스처 동반")을 자동으로 강제했습니다.
2.8 마지막 대조 — /speckit.converge
구현이 "끝난 것 같을" 때 converge를 돌렸습니다. 이게 단순 "다 됐나요?" 확인이 아니라, 코드베이스를 산출물과 대조해 빠진 일을 작업으로 되돌려 놓는 단계라는 게 핵심입니다. converge가 회수한 잔여 작업:
- 알림 디듀프는 구현됐지만 복구(resolved) 알림(clarify에서 합의한 1회 복구 알림)이 누락 → 신규 작업으로 추가.
research.md가 언급한 "검사 결과 보존 기간(retention)" 정책이 코드에 없음 → 작업화.
converge가 없었다면 이 둘은 "나중에 누가 발견"할 부채로 남았을 겁니다.
3. 정직한 숫자와 트레이드오프
이제 가장 민감한 질문입니다. 그래서 시간이 어디에 갔나? 명세에 들인 선불 비용은 본전을 뽑았나? 다시 강조하지만 아래 수치는 한 번의 작업을 정리한 예시값입니다.
3.1 단계별 시간 배분 (예시)
| 단계 | 대략 비중 | 성격 |
|---|---|---|
| constitution | 5% | 한 번 쓰면 시리즈 내내 재사용 |
| specify | 12% | 사람이 생각을 정리하는 시간 |
| clarify | 13% | 질문에 답하는 시간 (높아 보이지만 후반 재작업을 산다) |
| plan | 15% | AI 주도, 사람은 검토 |
| tasks | 8% | 거의 자동 |
| analyze | 7% | 짧지만 회수율 높음 |
| implement | 35% | 실제 코딩 |
| converge | 5% | 마무리 회수 |
눈에 띄는 건 명세·명료화·분석에 합쳐서 약 1/3(specify+clarify+analyze ≈ 32%)이 갔다는 점입니다. 바이브 코딩이라면 이 1/3을 통째로 건너뛰고 바로 implement로 갈 수 있습니다. 그게 SDD의 선불 비용입니다. 정직하게 말하면, 작은 작업에서는 이 선불이 그냥 손해입니다.
3.2 그 선불이 뒤에서 사 준 것
대신 이 선불은 후반에서 세 가지로 회수됐습니다.
- 재작업 감소: analyze가 2건, converge가 2건의 결함을 "코드 작성 전/직후"에 잡았습니다. 같은 결함을 통합 테스트 단계에서 발견했다면 디버깅·재구현 비용은 몇 배가 됩니다.
- 리뷰 속도: 모든 코드가
T00n → US-n로 추적되니, 리뷰어가 "이게 왜 필요한지"를 묻는 왕복이 거의 없었습니다. - 재진입 비용 제로화: 며칠 뒤 돌아와도
spec.md만 읽으면 맥락이 복원됩니다(1부 "맥락 유실"의 구조적 해소).
3.3 같은 기능, 두 방식
| 항목 | 바이브 코딩 | SDD |
|---|---|---|
| 첫 동작까지 시간 | 빠름 | 느림 (명세 단계 선불) |
| 두 번째 요청의 안정성 | 깨지기 쉬움 | 안정적 (명세 기준 존재) |
| 결함 발견 시점 | 통합/운영 단계(늦음) | analyze·converge(이름) |
| 리뷰 가능성 | "느낌상" | 명세 대조 가능 |
| 며칠 뒤 재진입 | 맥락 재구축 필요 | spec.md 읽으면 복원 |
| 팀 협업 | 구두 합의 | 파일 = 계약 |
| 일회성 스크립트 | 이김 | 오버헤드만 |
| 다회성 프로덕션 기능 | 부채 누적 | 이김 |
결론은 단순합니다. SDD에는 분명한 오버헤드가 있고, 그 오버헤드는 "두 번째 요청"이 올 일에서만 본전을 뽑습니다. 두 번째 요청이 영영 안 올 일이라면 SDD는 과합니다. 이 판단이 5절의 핵심입니다.
4. 우리가 밟은 함정 (가장 값진 부분)
매끈한 성공담보다 값진 건 실패담입니다. dq-monitor를 만들며 실제로 넘어진 다섯 지점과, 그걸 어떻게 일으켜 세웠는지를 교훈 형태로 남깁니다.
함정 1 — 명세에 기술이 새어 들어감
첫 specify 초안에서 우리는 US-1을 "Postgres 테이블의 updated_at을 폴링해 신선도를 본다"라고 적었습니다. 보이시나요? "무엇"이어야 할 자리에 "어떻게"(Postgres, updated_at 폴링)가 들어갔습니다.
증상: 명세가 특정 구현을 전제하면, plan 단계의 설계 자유도가 사라지고, 나중에 기술을 바꿀 때 명세까지 같이 고쳐야 합니다. 교정: US-1을 "테이블 신선도가 SLA를 넘기면 감지한다"로 되돌리고, "어떻게 신선도를 측정하나(updated_at? 메타데이터?)"는
clarify와plan으로 내렸습니다. 교훈: spec에서 고유명사(제품·라이브러리·컬럼명)가 보이면 의심하라. 그건 대개 plan으로 내려가야 할 결정이다.
함정 2 — clarify를 건너뜀
한번은 "이건 명확하니까"라며 clarify 없이 작은 후속 기능(알림 채널 추가)을 바로 plan으로 보냈습니다. 그 결과 implement가 알림 실패 시 재시도 정책을 멋대로 만들었습니다(무한 재시도 → 운영에서 알림 폭주 위험).
증상: "명확하다"는 사람의 착각. 사람에게 자명한 결정(재시도 횟수, 백오프)이 AI에겐 빈칸이고, AI는 빈칸을 그럴듯하게 채웁니다. 교정: 재시도 정책을 clarify 항목으로 끌어올려 "최대 3회, 지수 백오프, 이후 dead-letter"로 명문화. 교훈: clarify는 "복잡한 기능용"이 아니라 "사람이 무의식적으로 가정하는 결정이 있는 기능용"이다. 거의 모든 기능에 해당한다.
함정 3 — 작업이 너무 굵음
초기 tasks.md엔 "검사 엔진 구현"이라는 단일 작업(T0xx)이 있었습니다. implement가 이걸 받자 신선도·정합성·이상치 셋을 한 덩어리로 짰고, 중간 검증 지점이 사라졌습니다. 한 곳이 틀리면 어디서부터 틀렸는지 추적이 어려웠습니다.
증상: 굵은 작업 = 큰 한 방 = 검증 불가. SDD의 본질인 "단계별 검증"이 작업 입도에서 무너짐. 교정: T006 하나를 신선도/정합성/이상치 + 각 픽스처로 분할(현재의 T004~T006). 각 작업이 독립적으로 초록불이 되게. 교훈: 작업은 "한 번에 리뷰 가능한 크기"가 상한이다. 한 작업이 여러 유저 스토리를 건드리면 쪼개라.
함정 4 — converge 없이 implement 산출물을 수용
dq-monitor 첫 사이클에서 우리는 implement가 "끝났다"고 하자 그대로 받았습니다. converge를 돌렸더니 §2.8의 그 두 항목(복구 알림, retention)이 조용히 빠져 있었습니다. "동작하는 것처럼 보이는 코드"와 "명세를 만족하는 코드"는 다릅니다.
증상: implement는 자신이 한 일만 보고합니다. 하지 않은 일은 보고하지 않습니다. 그 공백을 사람이 메우려면 산출물 전체를 다시 읽어야 하는데, 그걸 자동화한 게 converge입니다. 교정: implement 직후 converge를 의무 단계로 고정. converge가 회수한 잔여를 새 작업으로 받아 한 사이클 더. 교훈: implement의 "완료"는 제안이지 선언이 아니다. converge로 명세와 대조하기 전엔 끝난 게 아니다.
함정 5 — 아무도 지키지 않는 헌법
3부에서 멋지게 세운 헌법을, 정작 초기 implement는 거의 인용하지 않았습니다. "성능 5분" 원칙이 있는데도 첫 이상치 검사는 행 단위 루프로 짜여 느렸습니다. 헌법이 파일로만 존재하고 프롬프트로 연결되지 않으면 장식입니다.
증상: 헌법이 implement의 컨텍스트에 실질적으로 들어가지 않으면, AI는 그 원칙을 모릅니다. 교정: plan·tasks 단계에서 각 작업이 어떤 헌법 원칙을 충족/위반할 수 있는지 명시(예: T006에 "원칙 4: 벡터화 필수" 주석). analyze가 헌법 위반도 함께 검사하도록 체크리스트화. 교훈: 헌법은 "써 두는 것"이 아니라 "매 단계 인용되는 것"으로 살아 있어야 한다. 지켜지지 않는 원칙은 원칙이 아니다.
5. SDD를 켤 때와 과한 때
이 시리즈가 도구를 정직하게 소개하려면, "쓰지 말아야 할 때"도 분명히 말해야 합니다. 1부의 메시지를 케이스 스터디 경험으로 다시 벼립니다.
| 상황 | SDD? | 이유 |
|---|---|---|
| 여러 번 손볼 프로덕션 기능 | 예 | "두 번째 요청"이 반드시 온다. 명세 비용이 회수된다. |
| 요구사항에 모호성이 있는 기능 | 예 | clarify가 사람의 숨은 가정을 드러낸다. |
| 팀이 함께 다루는 코드 | 예 | 파일이 계약이 되어 구두 합의 증발을 막는다. |
| 며칠~몇 주짜리 작업 | 예 | 재진입 시 spec.md가 맥락을 복원한다. |
| 한 번 쓰고 버릴 스크립트 | 아니오 | 두 번째 요청이 없다. 선불이 그냥 손해. |
| 10줄짜리 버그 수정 | 아니오 | 명세 읽기보다 코드 보기가 빠르다. |
| 탐색적 프로토타이핑 초기 | 아니오/부분 | 무엇을 만들지 아직 모를 땐 명세가 발목을 잡는다. |
핵심 원칙 한 줄: 품질 게이트는 통행료가 아니라 다이얼입니다. constitution·clarify·analyze·checklist를 매번 의무로 켜는 게 SDD가 아니라, 작업의 무게에 맞춰 게이트를 켜고 끄는 판단이 SDD를 잘 쓰는 능력입니다. dq-monitor처럼 다회성·다인원·모호성 있는 일엔 전 게이트를 켜고, 10줄 패치엔 통째로 끄는 게 맞습니다.
6. 이번 주 바로 써먹는 도입 체크리스트
다음 기능 하나에 SDD를 시범 적용해 보고 싶은 분을 위한 실전 체크리스트입니다. 한 번에 다 하지 말고, 위에서부터 켜 보세요.
- 후보 기능을 고른다 — 두 번째 요청이 올 기능으로(일회성 스크립트 말고).
-
specifyCLI로 프로젝트에 SDD 스캐폴딩을 깐다 (2부 참고). -
/speckit.constitution으로 원칙 3~5개를 쓴다 — 짧게. 길면 아무도 안 읽는다. -
/speckit.specify로 기술 빼고 무엇·왜만 적는다. 고유명사가 보이면 plan으로 내린다(함정 1). -
/speckit.clarify를 건너뛰지 않는다. "명확하다"는 느낌을 의심한다(함정 2). -
/speckit.plan으로 아키텍처를 설계하고, 헌법 원칙을 각 설계 결정에 연결한다(함정 5). -
/speckit.tasks로 쪼개되, 한 작업이 한 번에 리뷰 가능한 크기인지 본다(함정 3). -
/speckit.analyze로 implement 전에 spec·plan·tasks를 교차검증한다. -
/speckit.implement를 작업 단위로 돌리고, 각 작업 끝에 테스트 초록불을 확인한다. -
/speckit.converge를 의무로 돌려 빠진 일을 회수한다. "끝난 것 같음"을 믿지 않는다(함정 4). - 한 사이클 돌린 뒤, 들인 시간과 회수된 재작업을 적어 본다 — 다음 기능의 게이트 다이얼 판단 근거가 된다.
7. 시리즈를 닫으며 — 7부의 아크
일곱 편을 하나의 아크로 되감습니다.
| 부 | 주제 | 한 줄 요약 | dq-monitor의 그 순간 |
|---|---|---|---|
| 1부 | 왜 SDD인가 | 바이브 코딩의 세 실패 모드, 명세 = 진실 | 문제 정의 |
| 2부 | 시작하기 | specify 설치·init·Claude Code 연동 | 빈 저장소 세팅 |
| 3부 | Constitution | 데이터 팀용 원칙 수립 | 정확성·관측·테스트·성능 원칙 |
| 4부 | Specify & Clarify | 무엇·왜 + 모호성 제거 | US-1~3, 임계값·디듀프 결정 |
| 5부 | Plan & Tasks | 아키텍처·작업·정합성 | plan/data-model/contracts, tasks, analyze |
| 6부 | Implement & Converge | 구현·이슈 연동·완료 검증 | 코드베이스 + 잔여 회수 |
| 7부 (이 글) | 실전 회고 | 0→1 케이스 스터디·함정·판단 | 전체 통합 회고 |
다시, 핵심 명제
시리즈를 관통하는 한 문장은 처음부터 끝까지 같았습니다.
진실의 원천은 코드가 아니라 명세다. 그 명세는 사람과 AI가 함께 읽고, 함께 검증하고, 함께 고치는 단 하나의 계약서다.
바이브 코딩이 "두 번째 요청"에서 무너지는 이유는 AI가 멍청해서가 아니라, 무엇이 맞는지 적어 둔 곳이 없어서였습니다. SDD는 그 빈자리에 명세를 놓습니다. dq-monitor의 여정 전체가 이 한 문장의 증명이었습니다. analyze가 결함을 잡은 것도, converge가 잔여를 회수한 것도, 며칠 뒤 spec.md만 읽고 맥락이 복원된 것도 — 전부 "명세라는 대조 기준이 존재했기 때문"입니다.
앞으로 — 팀으로 확장하기 (다음 이야기 예고)
이 시리즈는 한 명의 개발자가 한 기능을 SDD로 만드는 데까지 왔습니다. 진짜 도전은 그다음, 팀 전체가 일관된 방식으로 SDD를 돌리는 것입니다. Spec Kit은 이를 위한 확장 메커니즘을 갖고 있습니다.
- 익스텐션(extensions): 새로운 슬래시 커맨드를 추가해 팀 고유의 단계를 끼워 넣습니다.
- 프리셋(presets): 워크플로를 커스터마이즈해 "우리 팀은 항상 이 게이트를 켠다" 같은 기본값을 고정합니다.
- 번들(bundles): 익스텐션·프리셋·워크플로를 묶어 역할 기반으로 팀에 프로비저닝합니다. 데이터 엔지니어용 번들, 프런트엔드용 번들처럼.
그리고 이 모든 게 가능한 이유는 1부에서 본 그 사실, 산출물이 전부 평문 텍스트 파일이라 에이전트 잠금이 없다는 점입니다(30개 이상 에이전트 호환). 팀이 도구를 바꿔도, 명세·계획·작업이라는 자산은 그대로 따라옵니다.
이 "팀 단위 SDD 운영"은 그 자체로 한 시리즈 분량입니다. 다음 기회에 프리셋·번들로 데이터 팀의 표준 SDD 워크플로를 패키징하는 이야기로 다시 찾아오겠습니다. 일곱 편을 끝까지 함께해 주셔서 감사합니다. 이제, 여러분의 다음 기능에서 /speckit.specify 한 줄로 시작해 보세요.
참고 자료