바이브 코딩의 문제는 아니었다. 하지만 빠진 절반은 빌드 이전에 시작된다.
요약
본 글은 코딩 에이전트의 개발 과정에서 '빌드 전' 단계에 명세(Spec) 정의가 필수적임을 강조합니다. 기존 루프(Vibe → Build → Break...)를 확장하여, 인간이 의도와 경계를 먼저 정의하고 AI가 구축한 후 검증하는 역할 분담을 제안합니다.
핵심 포인트
- 코딩 에이전트 개발은 빌드 전 명세 단계부터 시작해야 한다.
- 명세를 미리 정의하면 아키텍처 부채를 줄이고 시스템 이해도를 높일 수 있다.
- AI의 역할을 '설계 및 구축'에서 '구축 지원'으로, 인간의 역할을 '의도와 경계 정의'로 재정립해야 한다.
왜 에이전트를 풀어놓기 전에 소프트웨어 엔지니어링이 바이브 코딩에 필요한가.
Don's loop는 빌드 후(post-build) 부분을 잘 다룬다.
하지만 코딩 에이전트의 경우, 우리가 그 단계에 도달하기도 전에 많은 문제가 발생할 수 있다고 생각한다.
Vibe Was Never the Problem: The Missing Half of Vibe Coding에서 Don Johnson은 바이브 코딩에서 잘못되는 것이 직관(intuition)이 아니라고 주장한다. 바로 직관에 멈추는 것이다.
그의 해결책은 다음과 같은 루프다:
Vibe → Build → Break → Understand → Stabilize → Perfect
나는 이 모든 것, 특히 Break → Understand → Stabilize 중간 과정에 거의 동의한다. 이것이 바로 많은 AI 지원 프로젝트가 건너뛰는 부분이다.
내가 추가하고 싶은 것은 순서(sequence)에 관한 것이다.
Don's loop는 결국 명세(spec)를 생성해낸다. 이는 테스트, 타입, 계약 등 실험을 신뢰할 수 있는 무언가로 바꾸는 것과 함께 Stabilize 단계에서 나타난다.
하지만 나는 그 명세의 어떤 버전이 빌드 후뿐만 아니라 빌드 전에도 존재해야 한다고 생각한다.
나의 버전은 다음과 같다:
Vibe → Spec → Break the Design → Build → Break the Build → Understand → Stabilize → Perfect
차이는 작아 보인다.
하지만 나는 그것이 매우 중요하다고 생각한다.
순서가 더 중요한 이유
Don은 완전한 이해(full understanding) 전에 탐색(exploration)을 할 필요성에 대해 좋은 주장을 펼친다.
조각가는 찰흙에 손대기 전에 조각상을 완전히 명세하지 않는다. 음악가도 베이스라인을 연주하기 전에 증명하지 않는다.
탐색에 대해서는 동의한다.
하지만 찰흙은 다시 모양을 만들기 쉽다.
그리고 찰흙은 당신이 커피를 마시는 동안 열두 개의 의존성(dependencies)을 설치해주지 않는다.
코딩 에이전트는 할 수 있다.
오늘의 한 Build 단계는 스무 개의 파일, 새로운 패키지, 인프라 구성(infrastructure configuration), 데이터베이스 마이그레이션(database migration), 인증 로직(authentication logic), 재시도(retries), 백그라운드 작업(background jobs), 그리고 때로는 스스로 추상화가 필요해 보이는 추상화 계층(abstraction)을 만들어낼 수 있다.
모든 것이 끝난 후에 이해가 온다면, 우리는 더 이상 단순히 생성된 코드를 검토하는 것이 아니다.
우리는 우리 자신의 시스템을 리버스 엔지니어링(reverse-engineering)하고 있는 것이다.
가벼운 사양(spec)을 미리 정의하는 것이 역할 분담 방식을 바꾼다.
이전에는:
AI가 설계 → AI가 구축 → 인간이 무슨 일이 일어났는지 발견
하지만 이제는:
인간이 의도와 경계를 정의 → AI가 구축 → 인간이 검증
이 단계가 없다면, 우리는 코드를 생성했던 어느 때보다 빠르게 아키텍처 부채(architectural debt)를 만들 수 있다.
나쁜 아키텍처도 매우 잘 테스트할 수 있다
여기서 Don의 Break 단계가 필요하지만 충분하지 않다고 생각한다.
구현을 깨보는 것(Breaking an implementation)은 다음 질문을 던진다:
이것이 실패하는가?
디자인 검토(design review)는 다른 질문을 한다:
애초에 이렇게 구축해야 했는가?
나는 경력 초기에 심혈관 장치 테스트를 주도하면서 이 교훈을 얻었다.
우리에게는 우리가 정의한 조건 하에서 장치가 올바르게 작동하는지 알려줄 수 있는 테스트 환경이 있었다.
문제는 그 조건 중 하나가 잘못되었다는 것이었다.
우리는 실제 운영 환경이 혈액(blood)을 포함하고, 이는 다르게 행동하는데도 물(water)을 사용하고 있었다.
우리는 계속해서 테스트할 수 있었고.
더 많은 테스트 케이스를 생성할 수도 있었다.
더 많은 데이터를 산출할 수도 있었다.
그리고 우리는 실제 환경을 충분히 대표하지 못하는 시스템 모델에 대해 점점 더 큰 확신을 갖게 되었을 것이다.
중요한 질문은 테스트 이전에 나와야 했다:
이 테스트 환경이 우리가 설계하려는 시스템을 실제로 대표하는가?
그 경험은 나에게 오래 남았다. 왜냐하면 팀이 시스템 수준의 가정(assumption)을 놓치면서도 구현을 얼마나 쉽게 검증할 수 있는지 보여주었기 때문이다.
때로는 가장 먼저 깨야 할 것이 코드가 아니다.
문제에 대한 모델이다.
같은 문제는 AI 시스템에서 훨씬 더 중요해진다.
민감한 기업 문서를 처리하는 애플리케이션을 상상해보라.
검색 엔드포인트(retrieval endpoints)를 퍼징(fuzz), 적대적 프롬프트(adversarial prompts)를 실행하고, 지연 시간(latency)을 테스트하여 우수한 커버리지(coverage)를 달성할 수 있다.
하지만 그 어떤 것도 애초에 민감한 문서가 특정 서비스 경계(service boundary)를 넘어서는 일이 없어야 하는 아키텍처를 고치지는 못한다.
이는 권한(authorization)이 권위 있는 출처(authoritative source)를 통해 확인되어야 할 때 두 번째 저장소에 복사되는 문제를 해결하지 못한다.
그리고 에이전트가 결코 필요하지 않았던 도구 권한(tool permission)을 부여하는 문제도 해결하지 못한다.
때로는 버그가 코드에 있는 것이 아니다.
아키텍처에 있다.
두 번 부수기 (Break twice)
그래서 나는 시스템을 두 번 부술 것이다.
첫 번째: 디자인을 부수기 (First: Break the design)
구현이 비용이 많이 들기 전에 하라.
가정(assumptions)들을 공격하라.
다음 질문들을 던져보라:
- 만약 이 가정이 틀렸다면?
- 10배 규모에서 무슨 일이 발생할까?
- 다운스트림 서비스(downstream service)를 사용할 수 없을 때는 어떻게 될까?
- 사용자가 악의적이라면?
- 모델이 확신에 차서 잘못되었다면?
- 신뢰 경계(trust boundaries)는 어디인가?
- 모델은 무엇을 결정해야 하는가?
- 무엇은 결정론적(deterministic)으로 유지되어야 하는가?
- 인간 검토(human review)가 필요한 것은 무엇인가?
- 우리가 최적화하는 것은 무엇인가?
- 우리는 무엇을 포기하고 있는가?
이것이 저렴한 '부수기'다.
아직 아무것도 존재하지 않는다.
잘못된 답변이라도 재작성(rewrite) 대신 화이트보드 수정만으로 비용을 절감할 수 있다.
다음: 빌드를 부수기 (Then: Break the build)
이것은 Don의 단계이며, 나는 이것을 유지할 것이다.
테스트하라.
퍼즈(Fuzz)하라.
실패를 주입하라.
공격하라.
부하 테스트(Load-test)를 하라.
보안 경계(security boundaries)를 테스트하라.
잘못된 입력값(malformed inputs)을 주어라.
적대적 입력값(adversarial inputs)을 주어라.
그리고 물론, 우편번호 필드에 이모지를 붙여넣는 사용자를 주어라.
두 '부수기' 단계는 서로 다른 질문에 답한다:
디자인 부수기: 이것이 올바른 시스템인가?
빌드 부수기: 우리가 그 시스템을 올바르게 구현했는가?
우리는 둘 다 필요하다.
탐색(exploration)이 끝나는 지점 (Where exploration ends)
이것들이 스펙(spec)이 있기 전에 빌드를 할 수 없다는 의미는 아니다.
버려도 되는 스파이크(spike)는 당연히 먼저 올 수 있다.
문제가 어떤 형태를 띠는지 발견하는 방식이라면, 오후에 세 가지 버전을 만들 수도 있다.
이것은 코딩 에이전트가 우리에게 주는 가장 흥미로운 것 중 하나다.
AI는 아키텍처 실험을 극적으로 저렴하게 만든다.
하지만 어느 시점부터 스파이크는 더 이상 실험이 아니라 다른 사람이 신뢰하거나, 운영하거나, 유지해야 할 무언가가 되기 시작한다.
그곳에 내가 스펙을 원하는 것이다.
스펙은 다음의 전환점을 표시한다:
**
AI는 그 질문의 경제학 자체를 변화시킵니다.
점점 더 어려운 질문들은 다른 곳으로 이동합니다:
이것을 구축해야 할까요?
시스템 경계는 무엇이어야 할까요?
모델은 무엇을 결정해야 할까요?
무엇은 여전히 결정론적(deterministic)이어야 할까요?
인간이 루프 안에 머물러야 하는 곳은 어디일까요?
프롬프트 대신 하드 컨트롤(hard control)이 필요한 곳은 어디일까요?
해피 패스(happy path)를 벗어났을 때 무슨 일이 발생할까요?
이것들은 엔지니어링 질문입니다.
이것들은 제품 질문입니다.
그리고 점점 더, 이것들은 거버넌스(governance) 질문이 됩니다.
또한, 이 질문들은 여러분이 먼저 답하지 않으면 코딩 에이전트가 기꺼이 대신 답변해 줄 수 있는 질문들입니다.
그것이 제가 우려하는 부분입니다.
AI가 코드를 작성할 수 있다는 점이 아닙니다.
단지 코드를 작성하는 것처럼 보이면서도 조용히 아키텍처적 결정을 내릴 수 있다는 점입니다.
바이브(Vibe)와 엔지니어링은 결코 반대편에 있지 않았다
저는 이 부분에서 Don의 의견에 강력하게 동의합니다.
바이브 코딩 대 소프트웨어 엔지니어링은 잘못된 선택(false choice)입니다.
바이브는 루프를 열어줍니다. (Vibe opens the loop.)
엔지니어링은 그 루프에서 나온 것이 배포할 가치가 있는지 여부를 결정합니다.
저는 이 주장을 한 단계 더 확장하고 싶습니다:
엔지니어링은 바이브가 끝날 때까지 기다려서는 안 됩니다. 그것을 둘러싸야 합니다.
프로토타입이 시스템이 되기 전에, 무엇을 만들고 있다고 생각하는지 적어보고 그 설계를 틀렸음을 증명하려고 노력하세요.
그런 다음 구축하십시오.
그리고 다시 구현(implementation)이 잘못되었음을 증명하려고 노력하세요.
AI는 소프트웨어 엔지니어링의 중요성을 떨어뜨리지 않았습니다.
단지 잘못된 것을 훨씬 더 빠르게 만들 수 있게 했을 뿐입니다.
어쩌면 그것이 바이브 코딩에 빠진 또 다른 절반일지도 모릅니다.
바이브가 적은 것이 아닙니다.
바이브를 둘러싼 더 많은 엔지니어링입니다.
여러분 차례입니다: 코딩 에이전트가 모든 테스트는 통과했지만 여전히 잘못된 경계, 가정 또는 아키텍처를 가진 무언가를 만들어낸 적이 있습니까? 무엇이 그것을 더 일찍 잡아냈을까요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기