"AI한테 명세를 어떻게 써줘야 제대로 코드가 나올까요?"
최근 가장 많이 받는 질문입니다. ChatGPT, Claude, Copilot... 다들 쓰고는 있는데, 원하는 결과가 안 나온다는 거죠.
비밀을 알려드릴게요: AI는 컴파일러처럼 생각하세요.
컴파일러에게 문법 틀린 코드를 주면? 에러가 나죠. AI도 마찬가지입니다. 명세가 모호하면 결과도 모호합니다.
사람을 위한 명세 vs AI를 위한 명세
10년 전과 지금의 차이를 보겠습니다.
10년 전: 사람이 읽는 명세
로그인 기능
- 이메일과 비밀번호로 로그인
- 성공시 대시보드로 이동
- 실패시 에러 표시
개발자가 알아서 나머지를 채워넣을 거라 기대했죠.
지금: AI가 읽는 명세
Function: authenticateUser
Method: POST /api/v1/auth/login
Input:
email:
type: string
format: email
required: true
validation: RFC 5322
example: "[email protected]"
password:
type: string
required: true
minLength: 8
maxLength: 128
validation:
- 최소 1개 대문자
- 최소 1개 숫자
- 최소 1개 특수문자
Output:
success:
status: 200
body:
token: string (JWT)
expiresIn: number (seconds)
refreshToken: string
failure:
status: 401
body:
error: "Invalid credentials"
code: "AUTH_FAILED"
Business Logic:
1. 이메일 존재 확인
2. 비밀번호 bcrypt 비교
3. 로그인 시도 기록
4. 5회 실패시 계정 잠금
5. JWT 토큰 발급 (1시간)
6. 리프레시 토큰 발급 (30일)
Error Cases:
- 이메일 없음: 404
- 비밀번호 틀림: 401
- 계정 잠김: 423
- 서버 에러: 500
차이가 보이시나요? AI는 암묵적 지식이 없습니다. 모든 걸 명시해야 합니다.
AI 친화적 명세의 5가지 원칙
1. 구조화 (Structured)
AI는 구조를 좋아합니다. 자유 형식보다는 정형화된 포맷을 사용하세요.
❌ 나쁜 예
사용자가 로그인하면 토큰을 주고 대시보드로 보내고
실패하면 에러 메시지를 보여주는데 5번 틀리면 잠그고...
✅ 좋은 예
Steps:
1. 입력 검증
2. DB 조회
3. 비밀번호 확인
4. 토큰 생성
5. 응답 반환
Error Handling:
- Case: 이메일 없음
Action: 404 반환
- Case: 비밀번호 틀림
Action: 401 반환, 시도 횟수 증가
2. 구체화 (Specific)
"적절히", "필요시", "일반적으로" 같은 모호한 표현은 금물입니다.
❌ 모호한 명세
- 적절한 검증 수행
- 필요시 캐싱
- 일반적인 에러 처리
✅ 구체적 명세
- 이메일: RFC 5322 형식 검증
- 캐싱: Redis, TTL 3600초
- 에러: 400(검증), 401(인증), 500(서버)
3. 예시 포함 (Examples)
AI는 예시를 통해 패턴을 학습합니다.
Examples:
Valid Input:
email: "[email protected]"
password: "SecurePass123!"
Expected Output:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 3600,
"refreshToken": "f47d3b2a-9c8e..."
}
Invalid Input:
email: "not-an-email"
password: "123"
Expected Error:
{
"errors": [
"Invalid email format",
"Password too short"
]
}
4. 제약사항 명시 (Constraints)
기술적, 비즈니스적 제약을 명확히 하세요.
Constraints:
Technical:
- Node.js 18+
- Express 4.x
- PostgreSQL 14+
- JWT (not sessions)
Business:
- 비밀번호 최소 8자
- 토큰 유효기간 1시간
- 동시 로그인 3개까지
- GDPR 준수
Performance:
- 응답시간 < 200ms
- 동시 요청 1000/s
5. 테스트 케이스 (Test Cases)
테스트 케이스를 명세에 포함하면 AI가 더 정확한 코드를 생성합니다.
Test Cases:
- name: "정상 로그인"
input: {email: "[email protected]", password: "Test123!"}
expected: {status: 200, hasToken: true}
- name: "잘못된 이메일"
input: {email: "invalid", password: "Test123!"}
expected: {status: 400, error: "Invalid email"}
- name: "계정 잠금"
setup: "5회 로그인 실패 후"
input: {email: "[email protected]", password: "Test123!"}
expected: {status: 423, error: "Account locked"}
실전: 결제 시스템 명세 작성
실제 프로젝트에서 사용한 명세입니다.
# 결제 처리 시스템 명세
## Overview
System: Payment Processing Service
Purpose: Stripe를 사용한 구독 결제 처리
Version: 1.0.0
## Architecture
```mermaid
graph LR
Client --> API
API --> Stripe
API --> Database
Stripe --> Webhook
Webhook --> API
``` {data-source-line="218"}
## API Endpoints
### 1. Create Subscription
POST /api/v1/subscriptions
Request:
headers:
Authorization: Bearer {token}
body:
planId: string # "basic" | "pro" | "enterprise"
paymentMethodId: string # Stripe payment method
couponCode?: string
Response:
200 OK:
subscriptionId: string
status: "active" | "trialing"
currentPeriodEnd: ISO8601
nextBillingDate: ISO8601
400 Bad Request:
error: "Invalid plan"
code: "INVALID_PLAN"
402 Payment Required:
error: "Payment failed"
code: "PAYMENT_FAILED"
declineCode: string
Business Rules:
1. 사용자당 1개 구독만 허용
2. 업그레이드는 즉시 적용, 다운그레이드는 다음 결제일
3. 3일 무료 체험 (카드 등록 필수)
4. 실패시 3회 재시도 (1일, 3일, 5일)
Implementation Details:
- Stripe Customer 생성/조회
- Payment Method 첨부
- Subscription 생성
- DB 저장 (subscriptions 테이블)
- 이메일 알림 발송
### 2. Cancel Subscription
DELETE /api/v1/subscriptions/{id}
Parameters:
id: string (subscription ID)
immediately?: boolean (default: false)
Response:
200 OK:
canceledAt: ISO8601
cancelAtPeriodEnd: boolean
Business Rules:
- 즉시 취소: 남은 기간 환불 없음
- 기간 종료 취소: 남은 기간 사용 가능
### 3. Webhook Handler
POST /api/v1/webhooks/stripe
Security:
- Stripe 서명 검증 필수
- IP 화이트리스트 (옵션)
Events:
customer.subscription.created:
- DB 상태 업데이트
- 환영 이메일 발송
customer.subscription.updated:
- 플랜 변경 처리
- 알림 발송
customer.subscription.deleted:
- 접근 권한 제거
- 취소 설문 이메일
invoice.payment_failed:
- 재시도 스케줄
- 경고 이메일
## Database Schema
```sql
CREATE TABLE subscriptions (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
stripe_subscription_id VARCHAR(255) UNIQUE,
stripe_customer_id VARCHAR(255),
plan_id VARCHAR(50),
status VARCHAR(50),
current_period_start TIMESTAMP,
current_period_end TIMESTAMP,
cancel_at_period_end BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_user_subscription ON subscriptions(user_id);
CREATE INDEX idx_stripe_subscription ON subscriptions(stripe_subscription_id);
``` {data-source-line="321"}
## Error Handling
```typescript
class PaymentError extends Error {
constructor(
message: string,
public code: string,
public statusCode: number,
public details?: any
) {
super(message);
}
}
// Usage
throw new PaymentError(
'Payment method declined',
'PAYMENT_DECLINED',
402,
{ declineCode: 'insufficient_funds' }
);
``` {data-source-line="344"}
## Testing
### Unit Tests
```typescript
describe('SubscriptionService', () => {
it('should create subscription for new user', async () => {
// Given
const userId = 'user123';
const planId = 'pro';
// When
const subscription = await service.create(userId, planId);
// Then
expect(subscription.status).toBe('active');
expect(subscription.planId).toBe('pro');
});
it('should prevent duplicate subscriptions', async () => {
// Given: user with existing subscription
// When: attempt to create another
// Then: throw error
});
});
``` {data-source-line="370"}
### Integration Tests
- Stripe Test Mode 사용
- Test 카드 번호 사용
- Webhook 시뮬레이션
## Monitoring
Metrics:
- 결제 성공률
- 평균 응답 시간
- 재시도 횟수
- 취소율
Alerts:
- 성공률 < 95%
- 응답시간 > 1초
- 5xx 에러 > 1%
이런 명세를 AI에게 주면, 프로덕션 레벨의 코드가 나옵니다.
AI별 명세 작성 팁
ChatGPT
- 대화형으로 점진적 개선
- "이전 코드를 기반으로..." 활용
- 컨텍스트 유지 중요
Claude
- 한 번에 전체 명세 제공
- 긴 문서도 잘 처리
- 구조화된 출력 요청
GitHub Copilot
- 주석으로 명세 작성
- 함수 시그니처 먼저 작성
- 테스트 먼저 작성하면 더 정확
명세 템플릿 모음
제가 실제 사용하는 템플릿들입니다:
API 엔드포인트
Endpoint: [METHOD] /path
Purpose: [한 줄 설명]
Authentication: [Required/Optional]
Request: [구조]
Response: [구조]
Errors: [에러 케이스]
Business Logic: [단계별]
데이터 모델
Model: [이름]
Table: [테이블명]
Fields:
- name: type, constraints
Relations:
- type: target
Indexes:
- fields
Validations:
- rules
비즈니스 로직
Function: [이름]
Input: [파라미터]
Output: [반환값]
Preconditions: [사전 조건]
Postconditions: [사후 조건]
Steps: [알고리즘]
Edge Cases: [예외 상황]
마무리: 명세는 투자다
"명세 쓸 시간에 코딩하는 게 빠르지 않나요?"
예전엔 그랬을지도 모릅니다. 하지만 AI 시대에는 다릅니다.
명세 작성 30분 = AI 코드 생성 3분 = 수동 코딩 3시간
명세를 잘 쓰면:
- AI가 정확한 코드 생성
- 팀원과 명확한 소통
- 문서화 자동 완성
- 테스트 케이스 명확
명세는 비용이 아니라 투자입니다.
특히 WBS와 결합하면 더 강력합니다. WBS의 각 태스크마다 명확한 명세를 작성하면, AI가 전체 프로젝트를 거의 자동으로 구현할 수 있습니다.
다음에 AI를 쓸 때는 "대충" 요청하지 마시고, 제대로 된 명세를 작성해보세요.
놀라운 결과를 보게 될 겁니다.
AI 시대의 프로젝트 관리와 명세 작성이 필요하신가요? Plexo를 확인해보세요.
댓글 없음:
댓글 쓰기