스펙 레이어
게시일: 2026년 4월 1일 | 원문 작성일: 2026년 4월 1일 | 저자: Matt Rickard | 원문 보기
핵심 요약
AI 에이전트가 코드를 잘 생성하게 됐지만, “맞는 것 같은데 틀린” 코드를 만드는 문제가 커지고 있어요. Spec-Driven Development(SDD)는 이 문제에 대한 해법이에요.
- 에이전트의 실패 방식이 다르다 — 빌드를 깨뜨리는 게 아니라, 실패하는 테스트를 비활성화하고, 기존 패턴을 무분별하게 재사용하고, 기존 동작을 건드리지 않고 새 경로를 추가해요.
- 실행 시점의 자유도가 너무 높다 — 의사결정이 문서화되지 않으면 에이전트가 매번 다시 결정해야 하고, 컴파일러와 테스트만으로는 “올바른 판단”을 검증할 수 없어요.
- 스펙은 의도를 좁히는 레이어 — 프로토콜 엔지니어링의 역사가 증명하듯, 명시적 인터페이스가 다양한 구현을 가능하게 해요. 스펙이 작을수록, 검증이 강할수록 좋아요.
• • •
AI 에이전트가 기능을 구현해요. 코드는 컴파일되고, 테스트는 통과해요. 그런데 핵심을 놓쳐요.
틀린 종류의 “맞음”이에요.
소프트웨어 도구 대부분은 인간이 저지르던 실수에 맞춰 만들어졌어요. 에이전트는 다른 방식으로 실패해요.
보통 빌드를 깨뜨리지 않아요. 실패하는 테스트를 비활성화해요. 가장 가까운 패턴을 재사용해요. 기존 경로를 보존하고 옆에 새 경로를 추가해요. 코드베이스가 “개별적으로는 타당해 보이는 실수들”로 채워지기 전까지는 모든 게 합리적으로 보여요.
익숙한 실패 패턴들이죠:
- 실패하는 테스트를 그냥 비활성화했어요.
- 기존 서비스를 그냥 재사용했어요.
- 기존 동작은 변경하지 않았어요.
- 맞아요. 그렇게 가정했어요…
결정이 문서화되지 않으면, 에이전트는 그 결정을 다시 내려야 해요. 컨텍스트 윈도우는 유한하고, 유한한 범위 안에서조차 완벽하지 않아요. 더 근본적인 문제는 실행 시점에 자유도가 너무 높다는 거예요.
컴파일러, 린터, 테스트가 도움이 되긴 해요. 구문 오류, 깨진 임포트, 실패하는 동작을 잡아주죠. 하지만 에이전트가 올바른 판단을 내렸는지 판별하기는 어려워요. 대규모 테스트 카탈로그조차 추가적 변경(additive change)에는 취약해요.
코드 생성이 제약 시스템보다 빠르게 발전했어요. 문제는 과소 제약된 실행이에요. 에이전트가 행동해야 하는 시점에서 자유도가 너무 높은 거죠. 의도를 문서화하는 것이 그 자유를 제약하는 한 가지 방법이에요. 스펙은 그걸 제공할 수 있는 하나의 레이어예요. 이 레이어의 역사적 근거는 프로토콜에서 가장 명확하게 나타나요.
• • •
프로토콜이라는 선례
프로토콜 엔지니어링이 가장 깔끔한 역사적 증거예요. 프로토콜이 기각된 대안을 전부 담고 있어서가 아니라, 여러 구현이 타겟으로 삼을 수 있는 인터페이스를 정의하기 때문이에요. RFC 7911이 1981년에 인터넷 프로토콜을 표준화했어요. HTTP 시맨틱스는 RFC 9110에 있고, TLS 1.3은 RFC 8446에 있어요. HTML은 WHATWG2가 리빙 스탠다드로 관리해요. 모든 경우에서, 스펙이 여러 구현의 독립적 진화를 가능하게 했어요.
하지만 스펙이 어려운 부분을 없애주지는 않아요. 다익스트라의 좁은 인터페이스 비판3은 코드를 산문으로 바꾼다고 정밀한 작업이 사라지지 않는다는 걸 보여줘요. Lamport4와 TLA+5는 구현 전에 명시적 불변량이 왜 여전히 중요한지 보여줘요. 모델 주도 개발6은 추상화를 너무 밀어붙이면 스펙 자체가 편집 대상이 되어버린다는 위험을 보여줘요.
목표는 실행 자유도를 줄이는 거예요.
• • •
스펙의 레이어들
”스펙”이라는 단어는 좀 과적되어 있어요. 시스템이 무엇을 해야 하는지, 이 코드베이스에서 어떻게 할 것인지, 작업 목록, 그리고 나중 변경에서도 살아남아야 할 규칙 — 이것들을 분리해야 해요.
각각이 다른 선택을 좁혀요.
| 레이어 | 제약 대상 | 역할 |
|---|---|---|
| 스펙 | 의도 | 시스템이 무엇을 해야 하는지 정의 |
| 플랜 | 접근 방식 | 이 코드베이스에서 어떻게 할 것인지 결정 |
| 태스크 | 순서 | 작업 목록과 실행 순서 명시 |
| 테스트/스키마/린트 | 동작 | 기계적으로 검증 가능한 규칙 강제 |
| 하네스 | 실행 | 나중 변경에서도 살아남아야 할 규칙 적용 |
• • •
현재 도구들의 접근
진짜 논쟁은 제약을 어디에 둘 것인가예요. GitHub Spec Kit과 Kiro는 변경 워크플로 가까이에 둬요: 하나의 작업에 대한 요구사항, 설계, 태스크. OpenSpec은 변경이 끝나도 살아남는 결정 기록으로 레포에 넣어요.
Tessl은 더 나아가서 스펙 자체가 편집 대상이 되어야 하는지 물어요 — 다익스트라의 반론이 가장 강하게 적용되는 지점이죠: “충분히 상세한 스펙은 코드다.” Intent는 스펙을 공유 상태로 취급해요. Symphony는 자율 실행을 위한 오케스트레이션 계약으로 취급해요.
각각이 에이전트를 다른 지점에서 고정하려고 해요.
제품 차이 아래에서, 이들은 같은 뼈대를 계속 재구축해요: 유지되는 컨텍스트, 기능 의도, 기술 플랜, 명시적 태스크, 그리고 검증. 목표는 에이전트에게 즉흥적으로 행동할 여지를 줄이는 거예요.
• • •
이상적인 모델
그래서 지금 시점에서 이상적인 모델은 어떤 모습일까요? 현재 도구들 대부분이 암시하는 것보다 작고, 의도와 실행 사이의 핸드오프가 더 깔끔한 형태예요.
스펙은 선언적이어야 해요. 그래야 에이전트가 취약한 패치 스크립트를 재생하는 대신 코드를 의도에 맞추게 돼요. 레이어로 나뉘어야 해요. 그래야 제품 요구사항이 슬며시 아키텍처가 되고, 기술 플랜이 슬며시 제품 범위를 추가하는 걸 막을 수 있어요. 그리고 수정 비용이 낮아야 해요. 스펙을 업데이트하거나 교체하거나 삭제하는 데 비용이 크면, 프로세스가 의식(ceremony)으로 굳어지고 의식이 곧 일이 돼요.
규칙을 기계적으로 강제할 수 있는 곳에서는 스펙 밖으로 빼서 린트, 스키마, 테스트, 또는 하네스로 옮겨야 해요. 산문은 줄이고, 강제는 늘리세요. 스펙은 중요하지만 하나의 레이어일 뿐이에요. 완전한 SDD는 작은 버그 수정, 빠른 프로토타입, 탐색적 UX에는 선택 사항으로 남아야 해요.
결국 성공하는 모델은 인간의 의도와 기계의 실행 사이에 좁은 인터페이스를 두는 거예요. 의도가 탐색 공간을 좁혀요. 코드, 테스트, 하네스가 동작을 지배해요. 더 작은 스펙, 더 강한 검증, 더 적은 추측.
역자 주
- RFC(Request for Comments): 인터넷 기술 표준을 정의하는 공식 문서 시리즈. IETF(Internet Engineering Task Force)가 관리하며, TCP/IP, HTTP 등 핵심 프로토콜이 모두 RFC로 표준화되었어요. ↩
- WHATWG(Web Hypertext Application Technology Working Group): Apple, Mozilla, Google, Microsoft 등이 참여하는 웹 표준 단체. W3C와 별도로 HTML 스펙을 “리빙 스탠다드”(버전 없이 지속 업데이트)로 관리해요. ↩
- 에츠허르 다익스트라(Edsger W. Dijkstra, 1930-2002): 네덜란드 컴퓨터 과학자. 최단 경로 알고리즘, 구조적 프로그래밍 등으로 유명하며, 소프트웨어 설계의 엄밀함을 강조한 것으로 잘 알려져 있어요. ↩
- 레슬리 램포트(Leslie Lamport): 분산 시스템 이론의 선구자로, 2013년 튜링상 수상자. LaTeX의 창시자이기도 해요. ↩
- TLA+(Temporal Logic of Actions): Lamport가 만든 형식 명세 언어. 시스템의 동작을 수학적으로 기술하고 모델 체킹으로 검증할 수 있어, Amazon 등에서 분산 시스템 설계에 활용해요. ↩
- 모델 주도 아키텍처(Model-Driven Architecture, MDA): OMG(Object Management Group)가 2001년에 제안한 소프트웨어 개발 방법론. 추상 모델에서 코드를 자동 생성하려 했으나, 모델 자체가 복잡해져 “코드 대신 모델을 편집하는” 상황이 되면서 기대만큼 확산되지 못했어요. ↩
참고: 이 글은 Matt Rickard가 자신의 Substack에 게시한 아티클을 번역한 것이에요.
원문: The Spec Layer - Matt Rickard (2026년 4월 1일)
생성: Claude (Anthropic)