[Spec Kit ④] Specify & Clarify — 명세 작성과 모호성 제거
기술 스택을 빼고 무엇·왜에만 집중해 명세를 쓰는 /speckit.specify, 빈틈을 순차 질문으로 메우는 /speckit.clarify, 그리고 품질을 게이트로 거는 /speckit.checklist를 dq-monitor 예제로 실습합니다.
3부에서 우리는 dq-monitor(실시간 데이터 품질 모니터링 서비스)의 헌법(constitution) 을 세웠습니다. 코드 품질·테스트·관측 가능성 같은 프로젝트를 관통하는 원칙이 .specify/memory/constitution.md에 박혔습니다. 이제 그 원칙 위에 "이 서비스가 무엇을 해야 하고 왜 필요한가"를 적을 차례입니다. 그런데 여기서 가장 흔한 실수가 시작됩니다 — 명세를 쓰랬더니 기술 스택부터 적는 것입니다. 이 글은 명세를 제대로 쓰는 법, 그리고 다 쓴 명세에서 모호성을 계획에 들어가기 전에 걷어내는 법에 관한 이야기입니다.
이 글에서 배우는 것
/speckit.specify의 황금률: 무엇·왜(요구사항·유저 스토리)에 집중하고 어떻게(기술 스택)는 미루는 이유dq-monitor의 실제 명세(spec.md) 예시 — 유저 스토리·기능 요구사항·테스트 가능한 수용 기준까지/speckit.clarify의 순차·커버리지 기반 질문이 모호한 요구사항을 어떻게 정밀하게 깎는지/speckit.checklist로 명세 자체의 품질을 검증하는 맞춤 체크리스트 만들기- specify → clarify → checklist가 계획으로 이어지는 루프와 흔한 함정
이 글은 Spec Kit 시리즈의 4부입니다. 3부에서 세운 헌법이 이번 단계의 든든한 가드레일이 됩니다.
1. /speckit.specify의 황금률 — 무엇·왜에만 집중하라
명세를 쓸 때 사람들이 가장 자주 저지르는 실수는, 머릿속에 이미 떠오른 해법을 명세에 적어버리는 것입니다. "PostgreSQL에 메트릭을 저장하고, Kafka로 이벤트를 흘리고, React 대시보드로 보여준다" — 이건 명세가 아니라 설계입니다. 그리고 이 단계에서 설계를 적어버리면 두 가지가 망가집니다.
첫째, 해법 공간을 너무 일찍 닫습니다. "Kafka로 이벤트를 흘린다"고 명세에 박는 순간, 정작 필요한 게 초당 수십 건짜리 폴링이었다는 사실은 영영 검토되지 못합니다. 무엇이 필요한지 합의하기도 전에 어떻게 만들지를 못 박으면, 더 단순하거나 더 적합한 대안은 시야에서 사라집니다.
둘째, 검증의 기준이 흐려집니다. 명세의 존재 이유는 "이 코드가 의도를 만족하는가"를 판단할 대조 기준을 만드는 것입니다. 그런데 명세에 "Kafka를 쓴다"가 들어가면, 그건 의도가 아니라 구현입니다. 나중에 "Kafka 안 썼으니 명세 위반"이라는 무의미한 리뷰가 생기거나, 반대로 진짜 의도("이벤트는 5초 안에 처리돼야 한다")가 명세에서 빠지게 됩니다.
그래서 Spec Kit의 /speckit.specify는 단 한 가지를 요구합니다.
무엇(What) 과 왜(Why) 만 적어라. 어떻게(How) 는
/speckit.plan단계로 미뤄라.
| 명세에 들어갈 것 (What/Why) | 명세에서 빼야 할 것 (How) |
|---|---|
| 유저 스토리("데이터 엔지니어로서 …하고 싶다") | 프레임워크·라이브러리 선택 |
| 기능 요구사항(신선도 검사, 이상치 알림 …) | 데이터베이스 종류·스키마 DDL |
| 비기능 요구사항(지연 한도, 가용성 목표) | API 엔드포인트 시그니처·클래스 구조 |
| 테스트 가능한 수용 기준 | 배포 토폴로지·인프라 구성 |
| 도메인 용어 정의 | 큐·캐시·메시지 버스 같은 미들웨어 지정 |
이 규율은 답답하게 느껴질 수 있습니다. 하지만 SDD의 핵심 통찰은 "한 방에 생성하지 않는다"는 것이었음을 떠올려 보세요. 명세 단계는 의도를 사람이 검토할 수 있는 형태로 고정하는 단계이지, 코드를 짜는 단계가 아닙니다. 기술 결정은 그것대로 충분한 무게를 가진 별도 단계(/speckit.plan)에서 다뤄집니다.
2. /speckit.specify 실행하기
3부에서 헌법까지 세팅된 dq-monitor 프로젝트에서, Claude Code에 /speckit.specify를 호출하고 자연어로 의도를 던집니다. 이때 프롬프트는 무엇·왜의 언어로 쓰는 게 핵심입니다.
/speckit.specify 데이터 엔지니어가 운영하는 데이터 파이프라인의 건강 상태를
실시간으로 감시하는 서비스를 만들고 싶다. 핵심은 세 가지다.
(1) 각 데이터셋의 "신선도" — 마지막 업데이트가 기대 주기보다 늦어지면 감지한다.
(2) "스키마/정합성" — 컬럼 누락·타입 변경·null 비율 급증 같은 구조적 이상을 감지한다.
(3) "이상치 알림" — 위 신호가 임계치를 넘으면 적절한 채널로 알림을 보낸다.
데이터 엔지니어는 데이터셋별로 임계치와 알림 채널(예: 이메일, 슬랙)을 직접 설정할 수 있어야 한다.
기술 스택은 아직 정하지 마라. 무엇을·왜에만 집중해 명세를 써라.명령이 끝나면 Spec Kit은 기능별 산출물 폴더를 만들고 그 안에 명세 파일을 생성합니다.
specs/
└── 001-dq-monitor/
└── spec.md # ← /speckit.specify 산출물 (이번에 생성)폴더 이름의
001-접두사는 기능 번호입니다. 한 저장소가 여러 기능을 SDD로 다룰 수 있으므로, 기능마다002-...,003-...처럼 번호가 붙은 독립 폴더를 갖습니다. 같은 폴더 안에 이후clarifications.md,plan.md,tasks.md,data-model.md,contracts/,research.md,quickstart.md가 쌓여 갑니다.
생성된 spec.md는 한 번에 완벽하지 않습니다. 그게 정상입니다. specify는 초안을 만드는 단계이고, 그 초안의 빈틈은 다음 절의 /speckit.clarify가 메웁니다. 먼저 그 초안이 어떻게 생겼는지 봅시다.
3. dq-monitor의 명세 예시 — spec.md
아래는 위 프롬프트로 생성·정리된 specs/001-dq-monitor/spec.md의 현실적인 예시입니다. 의도적으로 기술 스택이 단 한 줄도 없다는 점에 주목하세요. 신선도·정합성·임계치·알림은 모두 "무엇/왜"의 언어로만 기술됩니다.
# Feature Specification: 실시간 데이터 품질 모니터링 (dq-monitor)
## 1. 개요 (Overview)
데이터 엔지니어가 운영하는 데이터셋·파이프라인의 건강 상태를 지속적으로
감시하고, 이상 신호를 임계치 기반으로 감지해 설정된 채널로 알림을 보내는 서비스.
목표는 "장애를 사용자가 알아채기 전에 데이터 팀이 먼저 안다"이다.
## 2. 용어 (Glossary)
- **데이터셋(Dataset)**: 감시 대상이 되는 논리적 데이터 단위(테이블·토픽·파일 경로 등).
- **신선도(Freshness)**: 데이터셋이 마지막으로 갱신된 이후 경과 시간.
- **기대 주기(Expected Cadence)**: 데이터셋이 갱신돼야 하는 주기(예: 매시간, 매일 02:00).
- **정합성(Integrity)**: 스키마·값 분포가 합의된 계약을 따르는 정도.
- **알림 채널(Channel)**: 알림이 전달되는 목적지(예: 이메일, 메신저).
## 3. 유저 스토리 (User Stories)
- **US-1** 데이터 엔지니어로서, 각 데이터셋의 마지막 갱신 시각을 감시하고 싶다.
그래야 파이프라인이 멈췄을 때 지표가 오래되기 전에 대응할 수 있다.
- **US-2** 데이터 엔지니어로서, 스키마 변경(컬럼 추가/삭제/타입 변경)과
값 이상(예: null 비율 급증)을 감지하고 싶다. 그래야 다운스트림이
깨지기 전에 차단할 수 있다.
- **US-3** 데이터 엔지니어로서, 데이터셋마다 임계치를 직접 설정하고 싶다.
데이터셋마다 정상 범위가 다르기 때문이다.
- **US-4** 데이터 엔지니어로서, 이상이 감지되면 내가 지정한 채널로 알림을 받고 싶다.
그래야 대시보드를 계속 들여다보지 않아도 된다.
- **US-5** 온콜 담당자로서, 동일한 이상에 대한 알림이 반복 폭주하지 않기를 바란다.
그래야 진짜 새로운 문제에 집중할 수 있다.
## 4. 기능 요구사항 (Functional Requirements)
### FR-1 신선도 검사 (Freshness)
- FR-1.1 시스템은 각 데이터셋의 마지막 갱신 시각을 주기적으로 수집한다.
- FR-1.2 마지막 갱신 이후 경과 시간이 데이터셋의 기대 주기 + 허용 지연(grace)을
초과하면 "신선도 이상"으로 판정한다.
- FR-1.3 기대 주기와 허용 지연은 데이터셋별로 설정 가능해야 한다.
### FR-2 스키마/정합성 검사 (Schema & Integrity)
- FR-2.1 시스템은 데이터셋의 현재 스키마를 합의된 기준 스키마와 비교한다.
- FR-2.2 컬럼 추가·삭제·타입 변경을 구조적 이상으로 감지한다.
- FR-2.3 핵심 컬럼의 null 비율·고유값 수 등 분포 지표를 수집하고,
설정된 한계를 벗어나면 정합성 이상으로 판정한다.
### FR-3 이상치 판정 (Anomaly Thresholds)
- FR-3.1 각 검사는 데이터셋별로 설정된 임계치에 따라 정상/이상을 판정한다.
- FR-3.2 임계치는 절대값(예: null 비율 5% 초과)과 상대값(예: 직전
7일 평균 대비 3배)을 모두 지원한다.
- FR-3.3 임계치 미설정 시 시스템 기본값을 적용하되, 기본값을 명시한다.
### FR-4 알림 라우팅 (Alert Routing)
- FR-4.1 이상이 판정되면 해당 데이터셋에 설정된 채널로 알림을 발송한다.
- FR-4.2 알림에는 데이터셋, 이상 유형, 감지 시각, 관측값과 임계치가 포함된다.
- FR-4.3 동일 데이터셋·동일 이상 유형의 알림은 설정된 시간 창 동안
중복 제거(dedupe)하여 한 번만 보낸다.
- FR-4.4 이상이 해소되면 "복구(resolved)" 알림을 발송한다.
### FR-5 설정 (Configuration)
- FR-5.1 데이터 엔지니어는 데이터셋 목록과 각 데이터셋의 검사 항목,
임계치, 채널을 설정할 수 있다.
- FR-5.2 설정 변경은 서비스 재시작 없이 반영되어야 한다.
- FR-5.3 잘못된 설정(예: 존재하지 않는 채널 참조)은 적용 전에 거부되고
사유가 보고된다.
## 5. 비기능 요구사항 (Non-Functional Requirements)
- NFR-1 이상 감지부터 알림 발송까지 지연은 검사 주기 + 1분 이내.
- NFR-2 100개 데이터셋을 동시에 감시할 때 검사 1회가 5분 안에 완료된다.
- NFR-3 알림 발송 실패 시 최소 3회 재시도하고, 끝내 실패하면 기록을 남긴다.
- NFR-4 모든 판정은 어떤 입력으로 어떤 결론에 이르렀는지 추적 가능해야 한다.
## 6. 수용 기준 (Acceptance Criteria)
- AC-1 (US-1) 기대 주기가 1시간인 데이터셋이 90분간 갱신되지 않으면,
허용 지연 10분 설정 하에서 신선도 이상이 정확히 1건 판정된다.
- AC-2 (US-2) 기준 스키마에 없던 컬럼이 추가되면 구조적 이상이 판정되고,
알림에 추가된 컬럼명이 포함된다.
- AC-3 (US-3) 동일 입력이라도 데이터셋 A(임계치 5%)와 B(임계치 20%)에
서로 다른 판정이 내려진다.
- AC-4 (US-4) 이상 판정 시 해당 데이터셋에 설정된 모든 채널로 알림이
발송되고, 미설정 채널로는 발송되지 않는다.
- AC-5 (US-5) 같은 이상이 dedupe 창(예: 30분) 안에 5회 감지돼도
알림은 1회만 발송된다.
- AC-6 (FR-4.4) 이상 상태가 정상으로 돌아오면 복구 알림이 1회 발송된다.
## 7. 범위 밖 (Out of Scope)
- 이상의 근본 원인 자동 진단(root-cause analysis).
- 데이터 자체의 자동 수정·백필.
- 과거 데이터에 대한 소급 감시(초기 버전은 현재 시점부터).
## 8. 미해결/모호 항목 (Open Questions) ← clarify 단계에서 해소
- Q1 "기대 주기"를 사람이 일일이 설정하나, 과거 갱신 이력에서 추론하나?
- Q2 알림 dedupe 창의 기본값은 얼마인가?
- Q3 채널은 어디까지 지원하나(이메일만? 메신저 포함?)?
- Q4 검사 실패(데이터 소스 접근 불가)는 "이상"인가 별도 "오류"인가?이 명세에서 두 가지를 눈여겨보세요.
- 수용 기준이 테스트 가능합니다. "신선도를 잘 감지한다" 같은 모호한 문장이 아니라, "기대 주기 1시간, 허용 지연 10분일 때 90분 미갱신 → 이상 1건"처럼 입력과 기대 출력이 명시됩니다. 이게 나중에
/speckit.tasks에서 테스트로 직결됩니다. - 마지막에
Open Questions절이 있습니다. specify는 모르는 것을 아는 척하지 않습니다. 빈틈을 솔직히 남겨두고, 그 빈틈은 다음 절에서/speckit.clarify가 채워 넣습니다.
4. /speckit.clarify — 계획 전에 모호성을 걷어낸다
명세 초안에는 거의 항상 빈틈이 있습니다. 사람이 "당연하다"고 여겨 적지 않은 가정, 두 가지로 읽히는 문장, 숫자가 빠진 임계치. 이 빈틈을 그대로 두고 /speckit.plan으로 넘어가면, 계획 단계에서 AI가 빈틈을 제멋대로 메웁니다. 그리고 그 즉흥적 결정은 코드까지 흘러가, 나중에 "이거 누가 이렇게 하라고 했지?"라는 질문 앞에서 책임 소재를 잃습니다.
/speckit.clarify는 이 문제를 계획에 들어가기 전에 해결합니다. 동작 방식은 다음과 같습니다.
- 순차적(sequential): 한 번에 질문 폭탄을 던지지 않고, 한 질문씩 답을 받아 다음 질문을 조정합니다.
- 커버리지 기반(coverage-based): 명세를 영역별(데이터 모델·에러 처리·경계 조건·비기능 요구사항 등)로 훑어 가장 덜 명세된 곳을 우선 캐묻습니다.
- 기록(recorded): 사람의 답은
specs/001-dq-monitor/clarifications.md에 결정으로 적혀, 이후 단계가 참조하는 공식 기록이 됩니다.
예시 Q&A 흐름
/speckit.clarify
[Clarify] 명세를 검토했습니다. 모호하거나 미명세된 영역을 순서대로 질문하겠습니다.
Q1 (영역: 설정 / FR-1.3) "기대 주기(expected cadence)"는 데이터 엔지니어가
데이터셋마다 명시적으로 설정합니까, 아니면 과거 갱신 이력에서 자동 추론합니까?
- (A) 항상 수동 설정
- (B) 자동 추론, 수동 오버라이드 가능
- (C) 둘 다 지원하되 기본은 수동
> B
✓ 기록: 기대 주기는 과거 갱신 이력에서 추론하되, 데이터셋별 수동
오버라이드를 허용한다. 추론에는 최소 N회의 이력이 필요하며, 이력이
부족하면 수동 설정을 요구한다. (FR-1.3 갱신)
Q2 (영역: 알림 / FR-4.3) 알림 중복 제거(dedupe) 시간 창의 기본값은
얼마로 합니까? 또한 이 값은 데이터셋별로 재정의 가능합니까?
> 기본 30분, 데이터셋별 재정의 가능
✓ 기록: dedupe 기본 창 = 30분, 데이터셋별 오버라이드 허용. (FR-4.3 갱신)
Q3 (영역: 알림 채널 / FR-4.1) 초기 버전이 지원할 채널 범위는?
- (A) 이메일만
- (B) 이메일 + 메신저(웹훅)
- (C) 임의 웹훅(제너릭)
> B
✓ 기록: 초기 채널은 이메일과 메신저 웹훅 2종. 제너릭 웹훅은 범위 밖. (FR-4.1 갱신)
Q4 (영역: 경계 조건) 데이터 소스에 접근 자체가 실패하면(예: 권한·네트워크),
이를 "정합성 이상"으로 다룹니까, 별도의 "검사 오류"로 다룹니까?
> 별도의 검사 오류로. 이상과 구분해서 다른 채널로 보낼 수 있게.
✓ 기록: 검사 실패는 데이터 이상과 구분된 "검사 오류" 범주로 다룬다.
오류 알림은 이상 알림과 별도 라우팅 가능. (신규 FR-6 추가)
[Clarify] 핵심 모호성 4건이 해소되었습니다. clarifications.md에 기록하고
spec.md의 Open Questions를 갱신했습니다.모호함 → 정밀함: before / after
clarify의 효과를 한 요구사항으로 압축해 봅시다.
| 내용 | |
|---|---|
| Before (모호) | FR-1.3 "기대 주기와 허용 지연은 데이터셋별로 설정 가능해야 한다." — 누가 설정하는지, 자동 추론이 있는지, 이력이 없으면 어떻게 되는지 불명 |
| After (정밀) | FR-1.3 "기대 주기는 최근 N회 이상의 갱신 이력에서 자동 추론하며, 데이터셋별 수동 오버라이드를 허용한다. 이력이 N회 미만이면 추론하지 않고 수동 설정을 요구한다. 허용 지연은 항상 수동 설정이며 기본값 0." |
After는 data-model과 테스트로 곧장 번역됩니다. 추론에 필요한 N이라는 파라미터, 오버라이드 필드, "이력 부족" 분기까지 — 계획 단계가 추측할 필요가 없습니다. clarify에서 답한 한 문장이 plan에서 흔들릴 결정 열 개를 미리 못 박습니다.
clarify를 건너뛰면 그 비용은 사라지지 않고 계획 단계로 이연됩니다. plan에서 AI가 빈틈을 즉흥적으로 메우고, 그 즉흥은 tasks·코드까지 전파되며, 결국 가장 비싼 곳(구현 후 리뷰)에서 청구됩니다.
5. /speckit.checklist — 명세 자체의 품질을 게이트로 걸기
clarify가 "빠진 것을 채우는" 단계라면, /speckit.checklist는 "채워진 것이 충분한지 검사하는" 단계입니다. 명령은 명세와 명료화 결과를 읽고, 요구사항과 명확성을 검증하는 맞춤 체크리스트를 생성합니다. 이 체크리스트는 코드가 아니라 명세를 검사한다는 점이 핵심입니다 — "이 명세가 계획에 넘어가도 될 만큼 단단한가?"를 묻는 품질 게이트입니다.
/speckit.checklist 이 명세가 프로덕션 계획으로 넘어갈 준비가 됐는지
검증하는 품질 체크리스트를 만들어라. 요구사항의 완전성·테스트 가능성·
모호성 부재에 초점을 맞춰라.생성된 체크리스트 예시(specs/001-dq-monitor/에 저장):
# Spec Quality Checklist: dq-monitor (001)
## A. 요구사항 완전성 (Completeness)
- [ ] 모든 유저 스토리에 대응하는 기능 요구사항이 존재한다
- [ ] 신선도·정합성·이상치·알림·설정 5개 핵심 영역이 모두 다뤄진다
- [ ] 검사 실패(데이터 소스 접근 불가)에 대한 동작이 정의돼 있다
- [ ] 복구(resolved) 알림 동작이 정의돼 있다
## B. 명확성 / 모호성 제거 (Clarity)
- [ ] "기대 주기"의 결정 방식(수동/자동/혼합)이 명시돼 있다
- [ ] 모든 임계치에 단위와 기본값이 명시돼 있다
- [ ] dedupe 시간 창의 기본값과 재정의 가능 여부가 명시돼 있다
- [ ] 지원 알림 채널의 범위가 닫혀 있다(열린 "등등" 없음)
- [ ] Open Questions가 모두 해소되어 비어 있다
## C. 테스트 가능성 (Testability)
- [ ] 모든 수용 기준이 입력과 기대 출력으로 기술돼 있다
- [ ] 수용 기준에 측정 가능한 숫자(시간·비율·횟수)가 들어 있다
- [ ] 경계 조건(이력 부족, 임계치 미설정)에 대한 기대 동작이 있다
## D. 비기능 / 운영 (Non-Functional)
- [ ] 감지→알림 지연 한도가 수치로 정의돼 있다
- [ ] 100개 데이터셋 규모에서의 성능 목표가 있다
- [ ] 알림 실패 재시도 정책이 정의돼 있다
- [ ] 헌법의 관측 가능성 원칙(추적성)이 NFR로 반영돼 있다
## E. 범위 (Scope)
- [ ] 범위 밖 항목이 명시되어 과도한 구현을 차단한다
- [ ] 범위 밖 항목이 어떤 유저 스토리와도 모순되지 않는다체크리스트의 모든 항목이 체크되면, 그제서야 명세는 계획으로 넘어갈 자격을 얻습니다. 체크되지 않은 항목이 있다면? 그건 specify나 clarify로 되돌아가야 한다는 신호입니다.
헌법 · clarify · checklist를 하나의 품질 게이트로
3개 도구는 따로 노는 게 아니라, 모호하거나 프로덕션급인 작업에 켜는 한 세트의 게이트입니다.
| 게이트 | 무엇을 보장하나 | 켜야 할 때 |
|---|---|---|
| 헌법 (3부) | 모든 단계가 동일한 원칙(품질·테스트·관측)을 따른다 | 팀·장기 프로젝트 |
| clarify | 명세에 즉흥으로 메울 빈틈이 남지 않는다 | 요구사항에 모호성이 있을 때 |
| checklist | 명세가 계획으로 넘어갈 만큼 단단하다 | 프로덕션으로 갈 기능 |
1부에서 강조했듯, 이 게이트들은 의무 통행료가 아니라 선택 가능한 품질 게이트입니다. 주말 프로토타입엔 끄고, 며칠 가는 프로덕션 기능엔 켭니다. 작업의 무게에 맞춰 게이트를 여닫는 판단이 곧 SDD를 잘 쓰는 능력입니다.
6. specify → clarify → checklist 루프
세 명령은 계획으로 넘어가기 전, 명세를 단단하게 만드는 하나의 루프를 이룹니다.
루프의 종료 조건은 명확합니다. 체크리스트의 모든 항목이 체크되고, Open Questions가 비었을 때 비로소 plan으로 넘어갑니다. 그 전까지는 specify ↔ clarify를 오가며 명세를 다듬습니다. 이 왕복이 귀찮아 보일 수 있지만, 여기서 깎아낸 모호성 하나하나가 계획·구현 단계에서 터질 폭탄을 미리 해체하는 것입니다.
7. 흔한 함정
명세 단계에서 반복적으로 관찰되는 세 가지 실패와 처방입니다.
함정 1 — 명세에 기술 결정을 흘린다
가장 흔합니다. "Redis로 임계치를 캐시한다", "이벤트를 Kafka 토픽으로 흘린다" 같은 문장이 슬그머니 명세에 들어옵니다. 이건 1절의 황금률을 정면으로 위반합니다.
- 증상: 명세에 제품명·프레임워크·DB·미들웨어가 등장한다.
- 처방: 그 문장을 "무엇이 필요한가"로 되번역한다. "Kafka로 흘린다" → "이벤트는 발생 후 5초 안에 처리돼야 한다". 기술 결정은 plan으로 옮긴다.
함정 2 — clarify를 건너뛰고 계획에서 비용을 치른다
"대충 명세 됐으니 바로 plan 가자"는 유혹입니다. 하지만 4절에서 봤듯, 메우지 않은 빈틈은 사라지는 게 아니라 계획 단계로 이연됩니다. AI가 빈틈을 즉흥적으로 메우고, 그 즉흥이 tasks·코드로 전파됩니다.
- 증상: plan/tasks 산출물에 명세 어디에도 없던 결정이 등장한다("그런데 이 retry 정책은 누가 정했지?").
- 처방: 의미 있는 모호성이 있는 작업이면 clarify를 게이트로 건다. clarify의 비용은 항상 plan 이후의 재작업 비용보다 싸다.
함정 3 — 테스트 불가능한 수용 기준
"신선도를 잘 감지한다", "알림이 적절히 간다" 같은 기준은 검증할 수 없습니다. 무엇으로 통과/실패를 가릴지가 없기 때문입니다.
- 증상: 수용 기준에 "잘", "적절히", "빠르게" 같은 형용사만 있고 숫자·입력·기대 출력이 없다.
- 처방: 모든 수용 기준을 (주어진 입력) → (기대 출력) 형태로 다시 쓴다. "빠르게" → "검사 주기 + 1분 이내". 이 형태라야
/speckit.tasks에서 테스트로 직결된다.
| 안티패턴 | 다시 쓰기 |
|---|---|
| "이상을 잘 감지한다" | "임계치 5%, 관측 7%일 때 정확히 1건의 이상이 판정된다" |
| "알림이 적절히 발송된다" | "이상 판정 시 설정된 모든 채널로 발송, 미설정 채널로는 미발송" |
| "성능이 충분하다" | "100개 데이터셋 1회 검사가 5분 이내 완료" |
마치며
명세 단계의 일은 코드를 적는 게 아니라 무엇·왜를 사람이 검토할 수 있게 고정하는 것입니다. /speckit.specify로 기술 스택을 배제한 초안을 쓰고, /speckit.clarify로 계획 전에 빈틈을 메우고, /speckit.checklist로 그 명세가 단단한지 게이트를 겁니다. 이 세 단계를 통과한 명세는 다음 단계가 추측 없이 일할 수 있는 단단한 계약서가 됩니다.
다음 5부에서는 드디어 어떻게(How) 로 넘어갑니다. /speckit.plan으로 dq-monitor의 아키텍처와 기술 스택을 설계하고, /speckit.tasks로 그 계획을 의존성 순서가 있는 실행 가능한 작업으로 분해한 뒤, /speckit.analyze로 spec·plan·tasks가 서로 모순되지 않는지 교차검증합니다. 우리가 4부에서 단단하게 깎아둔 명세가 거기서 빛을 발합니다.
참고 자료