2025-10-01

SDD 개발 방법론

Table of contents

참고

SDD란 무엇인가?

SDD(Specification-Driven Development)를 명세 기반 개발 방식이라고 직역하겠다.

기존의 명세 작성은 본격적인 개발에 앞서 필요한 작업 순서와 기술들에 관한 총체적 문서 작업으로 이루어졌다. 이 문서 작업은 시간도 오래 걸릴 뿐더러 실제 코드 작업 상 변경되는 부분이 많기 때문에 결국 코드보다 부차적인 것으로 간주되어 그 중요성이 떨어지는 것으로 치부됐다.

하지만 SDD에서는 명세를 기존과 같이 참고 용도로 보는 것이 아닌, 실제 구현되는 코드의 기반으로 사용되기 때문에 중요도가 과거의 개발 방식과 차원이 다르다. 이 SDD 개발 방식은 AI가 코딩 작업에 본격적으로 사용되면서 가능해졌다고 할 수 있는데, 각각의 명세에 따라 AI가 보조하여 문서를 작성하고 코드를 구현해 앱을 만들어 낸다. 기능의 추가/삭제 그리고 버그 수정 등도 코드에 대한 직접 수정이 아닌 명세 수정에 기반해 이루어지므로 앱은 명세와 뗄 수 없는 의존성을 가지게 된다.

SDD가 떠오르게 된 배경

첫째, AI의 능력이 자연어로 된 명세에 기반해 개발을 진행할 수 있을 정도로 신뢰할 수 있게 됐다.

둘째, 소프트웨어 복잡성이 급속도로 증가하고 있다. SDD는 AI에 기반한 체계적인 정렬을 통해 효과적으로 개발 효율을 올릴 수 있다.

셋째, 변화의 속도가 가파르게 증가하고 있다. 요구사항 변경이 점차 증가하면서 이에 대한 빠른 대응이 필요해졌다.

핵심 원칙

공통어(Lingua Franca)로써의 명세: 코드는 특정 언어와 프레임워크의 표현이다. 소프트웨어를 유지보수하는 것은 명세를 발전시키는 것이다.

실행 가능한 명세: 명세는 정확하고 완벽하고 모호하지 않아야 한다.

지속적인 정제: 지속적인 검증이 일어난다. AI는 명세의 모호성 모순점 그리고 진행되는 프로세스와의 차이를 분석한다.

리서치 기반 컨텍스트: 리서치 에이전트는 명세 프로세스를 관통하는 치명적 컨텍스트를 모은다(기술적 옵션, 퍼포먼스 영향 그리고 구조적 제한점).

양방향 피드백: 제품을 운영하면서 명세를 더 발전시킬 수 있는 정보를 얻을 수 있다. 업무 수행 메트릭스, 터지는 사건들 등은 명세를 더 발전시킬 수 있는 소스가 된다.

탐험을 위한 분기: 같은 명세를 사용해 여러개를 동시에 실행시키는 전략은 서로 다른 최적화 목표를 실험할 수 있게 한다(퍼포먼스, 유지보수, 유저경험, 비용 등).

필요 요소

  • 반복적 명세 개발을 위한 AI 어시스턴트
  • 기술 컨텍스트를 모으기 위한 리서치 에이전트
  • 명세를 번역해 실행하기 위한 코드 생성 도구
  • 명세 중심의 워크플로우를 적용하기 위한 버전 컨트롤 시스템
  • 명세 문서의 AI 분석을 통한 지속적 확인

여기서 중요한 점은 명세는 언제나 코드의 원천 소스로서 기능해야 한다.

명령어를 통한 SDD 효율화

SDD는 specification -> planning -> tasking 순으로 자동화 된다.

/specify 명령어

이 커맨드는 간단한 feature에 대한 서술을 완벽하고 구조화된 명세로 제공한다:

  1. 자동화된 특징 넘버링: 명세를 스캔해 다음 feature 번호를 할당한다.
  2. 브랜치 생성: 작성한 프롬프트에 기반해 의미있는 브랜치 이름을 만든다.
  3. 템플릿에 기반한 생성: 요구에 부합하는 feature 명세 템플릿을 복사하고 커스터마이즈한다.
  4. 디렉토리 구조: 모든 관계된 문서에 적절한 specs/[branch-name]구조를 생성한다.

/plan 명령어

Feature 명세가 존재하면, 이 명령어는 포괄적인 실행플랜(implementation plan)을 생성한다:

  1. 명세 분석: feature 요구사항과 유저 스토리 그리고 허용 조건을 이해하고 읽는다.
  2. 기본 원칙 준수: 프로젝트 기본 원칙과 구조적 원칙에 대한 조정을 확실히 한다.
  3. 기술적 해석: 비즈니스 요구사항을 기술적 구조와 실행 상세로 변환한다.
  4. 상세 문서: 데이터 모델, API 규약, 테스트 시나리오에 관한 지원 문서를 생성한다.
  5. Quickstart 검증: 핵심 검증 시나리오를 캡쳐해 가이드를 생성한다.

/tasks 명령어

이 명령어는 한 플랜이 생성된 후에 해당 플랜과 관련된 디자인 문서를 분석해 실행 가능한 태스크 리스트를 생성한다:

  1. 입력: plan.md (필수)를 읽고, data-model.md, contracts/, research.md도 존재한다면 함께 읽는다.
  2. 태스크 생성: 규약과 엔티티 그리고 시나리오를 특정 태스크로 변환한다.
  3. 병렬화: 독립적인 태스크는 [P]로 마크하고 안전한 병렬 그룹으로 묶는다.
  4. 결과: Feature 디렉토리 안에 tasks.md를 생성해 태스크 에이전트로 실행할 준비를 한다.

구조화된 자동화의 힘

이 명령어들은 단지 시간을 절약하는 것만이 아니라 지속성과 완전성을 강화한다:

  1. 상세사항을 놓치지 않음: 템플릿은 기능적이지 않은 요구사항부터 에러 핸들링까지 모든 측면이 고려되었음을 보장한다.
  2. 추적 가능한 결정사항: 모든 기술적 선택은 특정 요구사항과 연결된다.
  3. 살아있는 문서: 명세는 코드를 생성하므로 동기화된다.
  4. 재빠른 반복: 요구의 변경은 플랜을 수분 내에 재생성한다.

이 명령어들은 정적 문서보다 실행 가능한 실제적인 것을 생산하는 살아있는 문서로서 SDD 원칙을 구현한다.

템플릿에 의한 질적 향상

이 명령어들의 진정한 힘은 자동화만이 아니다. 템플릿이 어떻게 LLM으로 하여금 더욱 더 질 높은 명세를 만들 수 있도록 할 것인가를 판단하게 한다.

  1. 이르게 실행에 포커스를 두는 것을 예방하기

이 Feature 명세 템플릿은 명시적으로 다음을 가리킨다:

- ✅ Focus on WHAT users need and WHY
- ❌ Avoid HOW to implement (no tech stack, APIs, code structure)

이 제약은 LLM으로 하여금 적절한 추상 레벨을 유지하도록 한다. LLM이 자연스레 “리액트와 리덕스를 사용해 실행해라”로 점프하려는 경우, 템플릿은 “유저는 데이터에 대한 실시간 업데이트를 필요로 한다”를 주지시킨다. 그리고 이 분할은 실행 기술 산업이 변화하더라도 여전히 안정적으로 유지시킨다.

  1. 명시적 불확실성 마커를 강제하기

두 템플릿은 필수적으로 [NEEDS CLARIFICATION] 마커를 사용하게 한다:

When creating this spec from a user prompt:
1. **Mark all ambiguities**: Use [NEEDS CLARIFICATION: specific question]
2. **Don't guess**: If the prompt doesn't specify something, mark it

이는 LLM이 합리성을 가진 행위임을 가정한, 그러나 잠재적으로 불확실한 가정을 예방한다. “로그인 시스템이” 이메일/비밀번호 인증 방식을 사용할 것임을 추측하게 두지 않고 LLM이 [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]로 마크하도록 한다.

  1. 체크리스트를 통한 구조화된 생각하기

다음의 템플릿은 명세에 대해 “유닛 테스트”로 기능할 수 있는 포괄적인 체크리스트를 포함한다.

### Requirement Completeness
- [ ] No [NEEDS CLARIFICATION] markers remain
- [ ] Requirements are testable and unambiguous
- [ ] Success criteria are measurable

이 체크리스트들은 LLM이 아웃풋을 체계적으로 셀프 리뷰하도록 강제하고, 놓칠 수 있는 차이를 따라잡게 한다.

  1. 게이트를 통한 기본 원칙 준수하기

실행 플랜 템플릿은 페이즈 게이트를 통해 구조적 원칙을 강제한다.

### Phase -1: Pre-Implementation Gates
#### Simplicity Gate (Article VII)
- [ ] Using ≤3 projects?
- [ ] No future-proofing?
#### Anti-Abstraction Gate (Article VIII)
- [ ] Using framework directly?
- [ ] Single model representation?

이 게이트는 LLM이 명시적으로 복잡성을 정의하는 행위에서의 오버 엔지니어링을 예방한다. 만약 게이트가 실패하면 LLM은 “Complexity Tracking” 섹션에서 왜 실패했는지 기술해야 한다. 이를 통해 구조적 결정에 대한 책임을 생성할 수 있다.

  1. 위계적 상세 관리

다음의 템플릿은 적절한 정보 구조를 강제한다:

**IMPORTANT**: This implementation plan should remain high-level and readable.
Any code samples, detailed algorithms, or extensive technical specifications
must be placed in the appropriate `implementation-details/` file

이는 명세들이 읽을 수 없는 코드 쓰레기로 전락하는 문제를 예방한다. LLM은 적절히 자세한 수준을 유지하는 법을 배워 복잡한 것들을 별개의 파일로 구분하게 된다.

  1. 테스트를 우선해 생각하기

이 implementation template은 테스트 우선적 개발을 강제한다:

### File Creation Order
1. Create `contracts/` with API specifications
2. Create test files in order: contract → integration → e2e → unit
3. Create source files to make tests pass

이 순서 제약은 LLM으로 하여금 실행 전, 테스트 가능성과 규약에 대해 생각하게 한다. 이는 더 풍부하고 검증 가능한 명세를 만들도록 돕는다.

  1. 추측에 근거한 features를 예방하기

다음의 템플릿은 명시적으로 추측 가능성을 저하시킨다.

- [ ] No speculative or "might need" features
- [ ] All phases have clear prerequisites and deliverables

이 템플릿은 LLM이 “가지고 있으면 좋을” feature들을 더하는 것을 방지한다. 모든 feature는 구체적인 유저 스토리에 기반해 명백하게 수용 가능한 조건으로 역추적이 가능해야 한다.

복합적 효과

이러한 제한 사항들은 함께 다음의 명세들을 생산한다:

  • 완벽함: 체크리스트들이 확인해야 할 것들을 놓치지 않도록 한다.
  • 모호하지 않음: 강제화된 명시 마커들이 확실하지 않은 것들을 표시한다.
  • 테스트 가능함: Test first thinking이 프로세스에 녹아 있다.
  • 유지 가능함: 적절한 추상 레벨과 정보 위계가 있다.
  • 실행 가능함: 구체적인 결과물에 명확한 단계들이 있다.

이 템플릿들을 통해 LLM은 창의적인 작가의 모습에서 규칙화된 명세를 따르는 엔지니어로 탈바꿈 할 수 있다. 이는 LLM의 능력을 지속적으로 더 높은 퀄리티를 가진 결과물을 생산할 수 있도록 방향성을 주어, 실행 가능한 명세 기반 개발이 가능하게 한다.

핵심 규칙과 관계된 토대: 구조적 원칙을 강제하기

코드가 되는 명세들을 어떻게 다룰 것인지에 대한 변하지 않는 일련의 원칙들을 핵심 원칙(Constitution)이라고 하고, 이는 SDD의 핵심이라고 할 수 있다. 핵심 원칙은(memory/constitution.md) 시스템의 구조적 DNA처럼 기능하여 발생한 모든 실행에 대해 지속성, 간결성 그리고 퀄리티를 유지하게 한다.

개발의 9가지 조항

핵심 원칙은 모든 개발 프로세스의 측면을 형성하는 9가지 조항들을 정의한다:

조항(article) 1: Library first 원칙

모든 feature는 예외 없이 standalone 라이브러리로 시작해야 한다. 이는 시작부터 모듈러 디자인을 강제한다:

Every feature in Specify MUST begin its existence as a standalone library.
No feature shall be implemented directly within application code without
first being abstracted into a reusable library component.

이 원칙은 명세들이 하나의 덩어리(Monolithic) 어플리케이션 보다는 모듈 방식의 재사용 가능한 코드를 생성하도록 한다. LLM이 implementation plan을 생성할 때, 명확한 경계와 최소한의 의존성을 가진 라이브러리 형태의 feature들을 지향토록 한다.

조항 2: 인터페이스 권한

모든 라이브러리는 그 기능을 커맨드 라인 인터페이스를 통해 노출해야 한다:

All CLI interfaces MUST:
- Accept text as input (via stdin, arguments, or files)
- Produce text as output (via stdout)
- Support JSON format for structured data exchange

이는 관측 가능성과 테스트 가능성을 강화한다. LLM은 불투명한 클래스들 안에 기능을 숨길 수 없게 되어 텍스트 기반 인터페이스에 의해 모든 것에 접근 가능하고 검증 가능하게 된다.

조항 3: Test first 명령법

테스트 전에는 코드를 생성하지 않는다는 것으로 가장 변혁적 조항이다.

This is NON-NEGOTIABLE: All implementation MUST follow strict Test-Driven Development.
No implementation code shall be written before:
1. Unit tests are written
2. Tests are validated and approved by the user
3. Tests are confirmed to FAIL (Red phase)

코드를 생산하고 잘 되길 바라기 보다는 LLM은 납득할만한 테스트를 생성한 후에 실행문을 생성하게 된다.

조항 4 & 5: 간결성과 반추상화

이 두 가지 조항은 over-engineering에 대항한다:

Section 7.3: Minimal Project Structure
- Maximum 3 projects for initial implementation
- Additional projects require documented justification

Section 8.1: Framework Trust
- Use framework features directly rather than wrapping them

LLM이 자연스레 정교한 추상들을 생성할 때, 이 항목들이 복잡성을 가진 모든 레이어를 정의하도록 강제한다. Implementation plan 템플릿 중 “Phase -1 Gates”는 직접적으로 이 원칙들을 강화한다.

조항 6: Integration first 테스팅

고립화된 유닛 테스트를 넘어서 실제 환경의 테스팅에 우선순위를 둔다:

Tests MUST use realistic environments:
- Prefer real databases over mocks
- Use actual service instances over stubs
- Contract tests mandatory before implementation

이 조항은 이론이 아닌 실제에서 생성된 코드가 작동하는지 확인할 수 있게 한다.

템플릿들을 통한 핵심 규칙 강화

다음의 implementation plan 템플릿은 구체적 체크포인트들을 통해 위의 항목들을 운용할 수 있게 한다.

### Phase -1: Pre-Implementation Gates
#### Simplicity Gate (Article VII)
- [ ] Using ≤3 projects?
- [ ] No future-proofing?

#### Anti-Abstraction Gate (Article VIII)
- [ ] Using framework directly?
- [ ] Single model representation?

#### Integration-First Gate (Article IX)
- [ ] Contracts defined?
- [ ] Contract tests written?

이 게이트들은 구조적 원칙들에 대한 컴파일 타임 체크를 수행한다. LLM은 “복잡성 추적(Complexity Tracking)” 섹션에서 정의된 예외를 증명하거나 게이트들을 패싱하지 않고서는 실행되지 않는다.

불변 원칙의 힘

핵심 원칙의 힘은 변치 않는 것에 있다. 실행 상세에 대한 것들은 진화할 수 있지만 코어 원칙들은 상수로 남는다. 이는 다음을 제공한다:

  1. 시간을 가로지르는 지속성: 오늘 생성된 코드도 내년에 생성될 코드도 같은 규칙들을 따른다.
  2. LLM들을 가로지르는 지속성: 서로 다른 AI 모델들은 구조적으로 호환 가능한 코드를 생산한다.
  3. 구조적 무결성: 모든 feature는 시스템 디자인을 약화시키기보다 강화한다.
  4. 퀄리티 보증: 테스트 우선, 라이브러리 우선 그리고 간결성 원칙이 유지가능한 코드를 만들게 한다.

핵심 원칙의 진화

원칙들은 기본적으로 불변하지만 어플리케이션은 진화할 수 있다:

Section 4.2: Amendment Process
Modifications to this constitution require:
- Explicit documentation of the rationale for change
- Review and approval by project maintainers
- Backwards compatibility assessment

이를 통해 안전성을 유지하며 개선하는 것과 배우는 것을 하게 할 수 있다. 이 핵심 원칙은 오래된 것을 진화시켜 현실 세계에 기반한 새로운 원칙으로 변화될 수 있도록 한다.

규칙을 넘어서: 개발 철학

핵심 원칙은 단순히 규칙서가 아니다-이것은 LLM들이 어떻게 코드 생성을 하게 할지 청사진을 그리는 철학이라고 할 수 있다.

  • 불투명을 넘어선 관측 가능성: 모든 것은 CLI 인터페이스를 통해 점검 가능해야 한다.
  • 영리함을 넘어선 간결성: 간결하게 시작하고 필요한 것으로 증명 되었을 때만 복잡한 것을 추가한다.
  • 고립을 넘어선 통합: 인공적인 것이 아닌 현실 환경에서 테스트 한다.
  • 거대 덩어리가 아닌 모듈화: 모든 Feature는 명확한 경계를 가지고 라이브러리 형태로 존재해야 한다.

이러한 원칙들을 명세와 계획 프로세스에 끼워넣음으로써 SDD는 생성된 코드가 단순히 기능하는 것이 아닌-유지가능하고, 테스트 가능하고 그리고 구조적으로 건강하도록 한다. 핵심 원칙은 AI가 단순히 코드 생성기 역할을 하는 것으로부터 시스템 디자인 원칙들을 강화하고 존중하는 설계 동반자로 탈바꿈 시킨다.