포스트

Spec-kit만으로는 부족했다: 팀 병렬 개발을 위한 SDD 문서 구조 설계

Spec-kit만으로는 부족했다: 팀 병렬 개발을 위한 SDD 문서 구조 설계

최근 백엔드 개발자 4명이 모여 유튜버가 방문한 맛집 탐색 서비스의 MVP를 개발하기로 했다.

이 서비스의 핵심 기능은 다음과 같다.

  • 맛집 목록 조회 및 맛집 이름 검색
  • 지역별, 유튜버별, 음식 카테고리별 필터링
  • 맛집 상세 조회 및 방문한 유튜버 정보, 관련 영상 링크 확인
  • 관리자의 맛집·유튜버·영상 정보 등록

프로젝트를 시작할 때 이전 포스팅: 코드보다 먼저 명세를 정리한다는 것에서 다루었던 Spec-kit을 도입해 Spec-Driven Development(SDD) 방식으로 진행하면 쉽게 4명이 병렬로 개발할 수 있을 것이라 기대했다. 요구사항을 자연어로 작성하고 에이전트가 이를 구조화해주니 초반 속도가 매우 빠르게 붙는 것처럼 보였다.

하지만 팀원별로 작업을 나누고 동시에 개발에 들어가자마자 곧바로 벽에 부딪혔다. Spec-kit이 만들어 준 명세서만으로는 4명의 개발자와 여러 AI 에이전트가 충돌 없이 작업할 수 있는 경계가 충분히 형성되지 않았던 것이다.

이 글은 단순히 Spec-kit 사용법을 복습하는 차원을 넘어, 4명의 백엔드 개발자가 하나의 서비스를 병렬로 개발하기 위해 PRD, ADR, 컨벤션, 역할 분담을 어떻게 연결하고 문서 구조를 재설계했는지에 대한 고민 기록이다.


1. 하나의 큰 PRD가 부족했던 이유

처음에는 서비스 개요, MVP 기능 범위, 비기능 요구사항을 하나의 커다란 PRD(Product Requirement Document) 파일에 모두 몰아 넣었다. 문서 하나에 전체 그림이 그려져 있으니 당연히 팀원 모두가 동일한 이해를 바탕으로 개발을 시작할 수 있을 것이라 생각했다.

그러나 실제로 각 개발자가 개별 기능의 코드를 작성하려고 하자 다음과 같은 문제들이 쏟아졌다.

  • 기능의 존재 여부와 책임 소유권은 완전히 다른 문제였다. “유튜버별 맛집 조회” 기능이 PRD에 적혀 있었지만, 이를 유튜버 도메인 담당자가 개발해야 하는지, 맛집 도메인 담당자가 개발해야 하는지 명확하지 않았다.
  • 공통 엔티티 동시 수정 및 데이터 오염: Restaurant 엔티티 하나를 검색 담당자, 상세 조회 담당자, 관리자 등록 담당자가 동시에 수정하는 PR을 올리면서 엔티티 필드와 매핑 관계가 계속 충돌했다.
  • API 응답 및 비즈니스 규칙의 파편화: 맛집 목록 조회 시 데이터가 없을 때 200 OK 빈 배열을 줄 것인지, 404 Not Found 예외를 던질 것인지 개발자마다 다르게 구현했다.
  • 요구사항과 기술 선택의 혼재: PRD 안에 “PostgreSQL QueryDSL로 조회” 같은 구현 기술이 섞여 있어서 비즈니스 요구사항을 검토할 때 기술 결정 논의로 흐려졌다.
  • AI 에이전트의 임의 판단: 에이전트마다 서로 다른 패키지 구조와 DTO 설계, 예외 처리 패턴을 생성해 코드베이스 전체의 일관성이 무너졌다.

하나의 커다란 PRD는 서비스의 전체 방향성을 공유하는 데에는 훌륭하지만, 실제 구현 단위로 사용하기에는 책임과 변경 범위가 너무 넓다. 여러 명이 동시에 병렬 개발을 진행할 때는 단순히 “어떤 기능이 있는가”보다 다음과 같은 질문에 답할 수 있는 구체적인 문서 경계가 필수적이었다.

  • 누가 어떤 기능을 소유하는가
  • 어떤 도메인이 어떤 데이터를 관리하는가
  • 공통 엔티티를 누가 수정할 수 있는가
  • 기능 간 연결은 API 계약으로 어떻게 제한하는가
  • 공통 정책은 어디에 작성하는가

2. 기능 목록보다 도메인 경계를 먼저 정해야 했던 이유

문제의 원인을 분석해보니, 우리가 작업을 나눌 때 “맛집 검색 담당”, “상세 페이지 담당”, “등록 기능 담당”처럼 API 단위로만 개발을 나눴기 때문이었다. 이렇게 나누면 동일한 DB 테이블과 조회 로직을 여러 개발자가 동시에 건드리게 된다.

이를 해결하기 위해 기능 목록보다 도메인 경계소유 데이터를 먼저 정의했다.

  1. 맛집 탐색 도메인: 맛집 목록, 검색, 카테고리/지역 필터링 담당 (조회 중심 데이터 소유)
  2. 맛집 상세 및 콘텐츠 연결 도메인: 맛집 상세 정보, 매핑 데이터 담당
  3. 유튜버·영상 관리 도메인: 유튜버 프로필, 영상 URL 및 메타데이터 담당 (유튜버 데이터 소유)
  4. 관리자 데이터 등록 도메인: 맛집·유튜버·영상 신규 데이터 검증 및 백오피스 등록 담당

단일 PRD와 분리된 SDD 문서 구조 비교

도메인의 책임과 소유 데이터를 먼저 정하자, 각 팀원은 자신의 도메인 범위 안에서 독립적으로 엔티티와 비즈니스 로직을 구현할 수 있게 되었다. 다른 도메인의 데이터가 필요할 때는 직접 엔티티를 참조하거나 DB를 조회하는 대신, 명확히 정의된 Internal API나 인터페이스를 통해 요청하게 만들었다.

다만, 여기서 한 가지 중요한 판단을 내렸다. “도메인 경계를 나눈다고 해서 MSA(Microservice Architecture)로 가야 하는 것은 아니다.”

4명의 팀 규모에서 처음부터 마이크로서비스로 분리하고 네트워크 통신 환경을 구축하면 문서와 통신 비용만 기하급수적으로 증가한다. 따라서 MVP 단계에서는 완전한 마이크로서비스가 아니라, 단일 애플리케이션 내의 모듈 또는 패키지 수준 경계로 관리하는 것이 가장 현실적이라는 결론을 내렸다.


3. PRD의 역할: 기술 구현이 아닌 목적과 동작의 정의

문서 구조를 재설계하면서 가장 먼저 정리한 것은 PRD의 본질적인 역할이다. PRD는 “어떤 기술(QueryDSL, PostGIS 등)을 쓸 것인가”를 적는 문서가 아니라, “기능의 목적이 무엇이고 어떻게 동작해야 하는가”를 정의하는 문서여야 한다.

팀 내에서 정의한 PRD 필수 작성 항목은 다음과 같다.

  • 기능의 목적: 왜 이 기능이 필요한가
  • 사용자 흐름: 사용자가 어떤 순서로 진입하고 반응하는가
  • 기능 범위 및 입력/출력: 전달받는 파라미터와 결과 데이터
  • 비즈니스 규칙 및 예외 상황: 실패 시 처리 조건과 에러 기준
  • 완료 조건(Definition of Done): 어떤 상태일 때 구현 완료로 인정하는가
  • MVP 포함 여부 및 제외 범위: 이번 스코프에서 명확히 안 만드는 기능

예를 들어, 맛집 검색 PRD는 다음과 같이 작성했다.

  • 기능: 맛집 이름 부분 일치 검색 및 필터링
  • 입력 조건: 검색어(String), 지역ID(List), 유튜버ID(List), 카테고리ID(List)
  • 비즈니스 규칙: 여러 필터 조건은 AND 조건으로 조합 가능해야 함. 검색 결과가 없을 경우 HTTP 200과 함께 빈 목록과 안내 메시지를 반환함.
  • 제외 범위: 자연어 기반 키워드 검색 및 추천 알고리즘은 MVP 스코프에서 제외함.

이처럼 이전 포스팅: API 명세서 작성의 5단계 원칙에서 언급했듯, PRD에서는 구현 기술 명시를 철저히 배제하고 비즈니스 요구사항과 예외 처리 기준에 집중했다. 기술 선택은 완전히 다른 문서인 ADR로 넘겼다.


4. ADR의 역할: 기술 선택과 구현 제약의 명시

PRD가 “무엇을 만들 것인가”를 정한다면, ADR(Architecture Decision Record)은 “어떻게 구현할 것이며, 무엇을 하지 말아야 하는가”를 기록하고 제한하는 문서다.

ADR은 단순히 “Java 21을 쓴다”, “PostgreSQL을 쓴다” 같은 선택 결과만 나열해서는 안 된다. 선택 결과만 적어두면 개발자나 AI 에이전트가 세부 구현 방식을 임의로 해석하기 때문이다. 따라서 우리는 다음과 같은 표준 구조로 ADR을 작성했다.

  • Context: 어떤 기술적 문제나 배경이 있었는가
  • Decision: 무엇을 선택했는가
  • Alternatives: 어떤 대안들을 비교하고 배제했는가
  • Rationale: 왜 이 선택이 현재 4인 프로젝트 상황에 가장 적합한가
  • Consequences: 이 선택으로 얻는 장점과 감수해야 할 제약
  • Rules (필수): 개발자와 AI 에이전트가 코드를 작성할 때 반드시 지켜야 하는 규칙 및 금지 사항

실제 우리 서비스에 적용한 ADR 예시는 다음과 같다.

  • 동적 검색 쿼리: Spring Data JPA의 @Query나 메서드 이름 조합 대신 QueryDSL을 사용한다. (이유: 다중 필터 조합 시 쿼리 가독성 및 타입 안정성 확보)
  • 위치 기반 검색: PostgreSQL과 PostGIS를 사용한다. (이유: MVP 단계에서 별도 ES 구축 없이 DB 레벨 GIS 인덱싱 활용)
  • 패키지 구조: Layer 중심(controller, service, repository)이 아닌 Feature/Domain 중심(restaurant, creator, admin) 구조를 사용한다.
  • 도메인 참조 제약: 타 도메인 엔티티 직접 @ManyToOne 참조를 금지하고, ID 기반 참조 또는 Internal DTO를 통한 Accessor 인터페이스만 허용한다.
  • 언어 사양: Java 21 LTS를 사용하되, 가독성을 위해 Preview 기능 활용은 금지한다.

이처럼 적용 범위와 금지 사항(Rules)을 ADR에 명시하자, AI 에이전트가 갑자기 MyBatis를 도입하거나 엔티티 간 무분별한 양방향 매핑을 생성하는 불상사를 막을 수 있었다.


5. 컨벤션 문서가 별도로 필요한 이유

PRD와 ADR을 정했음에도 불구하고, 실제 코딩을 시작하니 매번 반복되는 소소한 규칙들에 대한 이견이 발생했다.

  • DTO 클래스 이름은 Request/Response로 끝낼 것인가, Command/Info로 끝낼 것인가?
  • 예외가 발생했을 때 글로벌 Response Body 포맷은 어떻게 통일할 것인가?
  • Git 브랜치 이름과 Commit 메시지 컨벤션은 어떻게 가져갈 것인가?

이런 반복 규칙까지 ADR에 담으면 ADR 문서가 너무 비대해진다. ADR은 중요한 기술적 아키텍처 결정을 기록하는 문서이고, 컨벤션(Conventions)은 매번 의사결정할 필요가 없는 단순 반복 규칙을 통일하는 문서다.

이전 포스팅: 협업을 하면서 처음 체감한 코드 컨벤션의 가치에서도 체감했듯이, 컨벤션 문서를 별도로 분리하여 다음 내용을 명확히 규정했다.

  • 코드 스타일 & Naming: Java Google Code Style 기반, DTO/Entity 생성 규칙
  • 예외 처리 규칙: GlobalExceptionHandler 공통 예외 응답 포맷
  • API URL Naming: 복수형 명사 사용, Kebab-case 적용
  • Git Workflows: feature/도메인명-기능명 브랜치 전략 및 PR 리뷰 규칙
  • 테스트 코드: Given-When-Then 구조 및 테스트 메서드 명명 규칙

6. 팀 병렬 개발을 위한 추천 문서 구조

이러한 고민을 바탕으로 구축한 최종 문서 directory 구조는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
docs/
├── product/
│   ├── overview.md
│   ├── mvp-scope.md
│   ├── domain-boundaries.md
│   └── business-rules.md
├── prd/
│   ├── restaurant/
│   │   ├── list.md
│   │   ├── search.md
│   │   └── detail.md
│   ├── creator/
│   │   └── creator-content.md
│   └── admin/
│       └── content-registration.md
├── adr/
│   ├── architecture/
│   ├── database/
│   ├── api/
│   ├── security/
│   └── infrastructure/
├── contracts/
│   ├── api/
│   └── events/
└── conventions/
    ├── code-convention.md
    ├── api-convention.md
    ├── test-convention.md
    └── git-workflow.md

SDD 문서 관계도

각 디렉터리는 다음과 같은 명확한 역할을 수행한다.

  • product/: 서비스의 전체 비전, MVP 범위, 도메인 경계 및 공통 비즈니스 정책 정의
  • prd/: 각 도메인별 세부 기능 요구사항과 완료 조건(DoD)
  • adr/: 아키텍처, DB, API 등 주요 기술적 결정 사항과 제약 규칙
  • contracts/: 팀원 간 개발 시 충돌을 방지하는 API 스펙 및 이벤트 계약 서식
  • conventions/: 코드 스타일, Git 워크플로우, 테스트 등 반복적인 개발 규칙

하지만 여기서도 점진적 적용(Progressive Adoption)이라는 현실적인 판단이 필요하다. 4명짜리 MVP 프로젝트 시작부터 위의 모든 문서를 풀(Full) 버전으로 채우려고 하면 개발도 시작하기 전에 문서 작성에 지쳐버린다.

따라서 우리는 초기에 overview.md, 핵심 도메인별 prd/, 굵직한 adr/, 기본 conventions/만 작성하고, 개발이 진행됨에 따라 필요 시 문서를 점진적으로 분리하고 확장하는 방식을 채택했다.


7. Spec-kit의 역할과 한계

그그렇다면 우리가 당초 사용하려고 했던 Spec-kit은 필요 없는 도구였을까? 전혀 그렇지 않다. Spec-kit의 진짜 가치와 한계를 정확히 구분하는 것이 중요하다.

Spec-kit이 잘하는 것

  • 비구조화된 자연어 아이디어를 명확한 구조(Constitution, Spec, Plan, Tasks)로 정리해주는 기능
  • 요구사항을 기반으로 구현 단계별 Task를 분해하고 연결해주는 자동화 작업
  • 1인 개발 또는 소규모 스코프에서 빠르게 뼈대를 잡는 작업

Spec-kit이 대신 해줄 수 없는 것 (팀이 직접 정해야 하는 것)

  • 도메인 경계와 책임 분담
  • 팀원별 엔티티 소유권 및 접근 제약
  • API 계약 인터페이스
  • 프로젝트 맥락에 맞는 아키텍처 결정 기준(ADR)
  • AI 에이전트가 넘지 말아야 할 금지 선(Boundary Rules)

결론적으로 Spec-kit팀의 병렬 개발 방식을 대신 결정해주는 도구가 아니다. 팀이 먼저 도메인 경계와 아키텍처 규칙을 합의하고, 이미 합의된 결정을 일관된 문서 형태로 구조화하고 추적할 때 최고의 위력을 발휘하는 도구다.


8. AI 에이전트를 사용할 때 문서 구조가 더 중요해지는 이유

사람 개발자는 대화 과정에서 자연스럽게 이전 맥락이나 팀 내 암묵적인 룰을 이해하고 적용한다. 하지만 AI 에이전트는 맥락에 대한 통찰이 아니라, 오직 제공된 문서와 코드 규칙만을 기준으로 판단한다.

문서 체계가 엉성하거나 금지 사항이 없으면, 에이전트는 다음과 같은 임의 판단을 내리게 된다.

  • 컨트롤러마다 DTO 재사용 방식을 제멋대로 변경함
  • 조회 성능을 높인답시고 타 도메인 엔티티를 직접 가져와 JPA 영속성 컨텍스트를 오염시킴
  • 예외 발생 시 에이전트 본인이 편한 형태의 커스텀 JSON 응답을 만들어냄
  • 검증되지 않은 외부 헬퍼 라이브러리를 임의로 Gradle에 추가함

따라서 AI 에이전트와 협업할 때는 단순한 자연어 설명보다 “해야 하는 것”, “하지 말아야 하는 것”, “변경 가능한 범위”, “충돌 시 우선순위”가 선명하게 적힌 ADR과 컨벤션이 필수적이다.

물론 모든 메서드의 내부 구현까지 문서로 빽빽하게 고정하면 개발의 유연성이 사라지고 문서 수정 비용이 커진다. 따라서 비즈니스 경계와 장기적 영향을 주는 기술 결정(도메인, DB, API 계약, 공통 규칙)만 문서로 단단히 고정하고, 메서드 내부의 구체적인 로직 작성은 개발자와 AI 에이전트의 자율에 맡기는 균형이 무엇보다 중요하다.


결론: 문서를 만드는 것이 아니라 경계를 만드는 것

이번 과정을 거치며 정리한 SDD 문서 체계의 핵심은 다음과 같다.

  • PRD: 무엇을 만들어야 하는지(목적과 동작)를 정의한다.
  • ADR: 중요한 구현 선택과 하지 말아야 할 제약을 정의한다.
  • 컨벤션: 매번 논의할 필요 없는 반복 개발 방식을 통일한다.
  • API 계약: 개발자 간, 도메인 간 연결 지점을 고정한다.
  • 도메인 경계: 팀원 간 코드 충돌과 오염을 방지한다.
  • Spec-kit: 이 결정된 내용들을 일관성 있게 구조화하도록 돕는다.

처음에는 SDD(Spec-Driven Development)가 그저 정해진 템플릿 양식에 맞춰 문서를 꼼꼼히 작성하는 개발 방법론이라고만 생각했다. 하지만 4명의 백엔드 개발자가 함께 서비스를 준비하면서 깨달은 진짜 핵심은 문서의 양이나 개수가 아니라 책임과 경계를 명확히 세우는 것이었다.

좋은 문서는 구현 방법을 깨알같이 나열하는 문서가 아니다. 여러 개발자와 AI 에이전트가 서로 다른 해석을 하지 않도록 선택지를 적절히 제한해주는 문서다. 제대로 정립된 SDD 문서 구조가 있었기에, 우리는 각자 맡은 도메인에만 집중하며 충돌 없는 병렬 개발을 진행할 수 있었다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.