본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 29. 03:24

주말 동안 '바이브 코딩(Vibe-coding)'으로 앱을 만들었다. 3주 후, 나는 그것을 설명할 수 없었다.

요약

AI 코딩 도구(Claude Code, Cursor)를 활용한 '바이브 코딩'이 개발 속도는 높여주지만, 코드의 설계 의도와 맥락을 소실시키는 문제를 지적합니다. AI 세션이 종료되면 결정의 근거가 사라져 디버깅과 코드 리뷰 시 역공학 비용이 발생한다는 점을 강조합니다.

핵심 포인트

  • AI 코딩 도구는 구현 속도는 빠르나 설계 의도를 기록하지 않음
  • 컨텍스트 손실로 인해 디버깅 및 코드 리뷰 시 역공학 비용 발생
  • Git은 변경 사항은 추적하지만, 변경 이유(Why)는 추적하지 못함
  • AI 세션의 휘발성이 협업과 유지보수에 미치는 부정적 영향

나는 주말 동안 '바이브 코딩(vibe-coded)'으로 만든 사이드 프로젝트의 Stripe 웹훅(webhook) 핸들러를 디버깅하고 있었다. 그 앱은 Claude Code로 만든 간단한 구독 결제 도구였다. 사용자 인증(user auth), 결제, 그리고 대시보드 기능을 갖추고 있었다. 잘 작동했다. 사용자들이 가입했고, 돈이 오갔다.

그러던 중 한 사용자가 요금제를 업그레이드한 후 결제가 두 번 되었다고 보고했다. 나는 웹훅 핸들러를 열고 그것을 뚫어지게 쳐다보았다. 명백한 버그는 없었다.

그 코드는 customer.subscription.updated 이벤트를 처리하고, 멱등성(idempotency)을 확인하며, 사용자 레코드를 업데이트했다. 모두 정확했다. 하지만 내가 알지 못하는 조건부 분기(conditional branch)가 있었다. 중복되는 결제 주기(overlapping billing cycles)를 확인하는 로직이었는데, 왜 그렇게 했는지 설명할 수 없었다. 나는 세션 중에 Claude와 이 부분을 논의했다는 것을 알고 있었다. 레이스 컨디션(race condition) 때문에 더 단순한 접근 방식을 거절했던 기억이 어렴풋이 났다. 하지만 어떤 접근 방식이었지? 왜 이 방식이었을까?

세션은 사라졌다. 커밋 메시지(commit message)에는 Add Stripe webhook handler라고 적혀 있었다. git diff는 무엇이 바뀌었는지는 보여주었다. 하지만 왜 바뀌었는지는 아무것도 보여주지 않았다.

나는 버그를 찾기 전까지 내 자신의 코드를 역공학(reverse-engineering)하는 데 거의 두 시간을 보냈다. 수정하는 데는 4분이 걸렸다.

이번이 처음이 아니었다. 일주일 전에는 지난 금요일에 Cursor로 시작했던 기능을 파악하려고 오전 내내 시간을 보냈다. 진전이 있었다는 것은 알고 있었고, 커밋 히스토리(commit history)에는 깔끔한 4개의 커밋이 남아 있었다. 하지만 속도 제한(rate limits)을 처리하기 위해 내가 선택한 접근 방식이 무엇인지, 왜 재시도 로직(retry logic)을 그런 식으로 구조화했는지 기억할 수 없었다. 그래서 나는 항상 결국 하게 되는 일을 했다. 새로운 세션을 시작하고 모든 것을 처음부터 다시 설명하는 것이었다.

문제는 AI 코딩 도구들이 만드는 부분(building part)에는 매우 뛰어나다는 점이다. 필요한 것을 설명하고, 반복(iterate)하고, 출시(ship)하면 된다. 하지만 그들은 아무것도 기억하지 못한다. 모든 세션은 제로(zero)에서 시작된다. 터미널을 닫으면 코드 뒤에 숨겨진 사고 과정은 사라진다. Git은 무엇이 변했는지는 추적한다. 하지만 왜 변했는지는 아무것도 추적하지 않는다. 그 비용이 얼마나 큰지 합산해 보기 전까지는 깨닫지 못한다.

주의를 기울이기 시작하면 어디에서나 나타난다

디버깅 세션만으로도 충분히 나빴다. 하지만 컨텍스트 손실(context loss)은 내가 예상하지 못한 방식으로 복리로 쌓여간다.

나는 Claude Code와 Cursor를 사용하는 팀원들의 PR(Pull Request)을 리뷰한다. Diff(차이점)는 깔끔하고, 구조가 잘 잡혀 있으며, 테스트도 통과한다. 하지만 나는 왜 이런 결정이 내려졌는지 알 수 없기 때문에 리뷰를 할 수가 없다. 직접적인 API 호출 대신 큐(queue)를 사용한 이유가 있었을까? 그것은 의도적인 선택이었을까, 아니면 단순히 AI가 처음으로 제안한 방식이었을까? 실제 리뷰를 시작하기도 전에 의도를 역공학(reverse-engineering)하는 데 20분을 소비한다. 그리고 그들도 내 PR을 보며 똑같은 일을 하고 있다는 것을 알고 있다.

세션 중간에 압축 벽(compaction wall)에 부딪힌 적이 셀 수 없이 많다. 작업 시작 2시간이 지나면, Claude는 나의 코드베이스, 제약 조건, 선호도를 이해한다. 그러다 컨텍스트 윈도우(context window)가 가득 찬다. 그러면 공간을 확보하기 위해 대화를 요약하기 시작하고, 그 과정에서 중요한 세부 사항들을 놓친다. AI는 스스로 모순된 말을 하기 시작하고, 한 시간 전에 설정한 제약 조건을 잊어버리며, 내가 이미 거절했던 방식을 제안한다. 마치 대화 도중에 협업자가 바뀌었는데 아무도 나에게 말해주지 않은 것과 같다.

나는 한 팀원이 내가 주로 AI로 구축한 코드베이스에 온보딩(onboarding)하려는 과정을 지켜보았다. 파일의 절반은 내가 더 이상 완전히 설명할 수 없는 결정들로 이루어져 있었다. 그 결정들이 나빠서가 아니라, 그 논리적 근거가 몇 주 전에 닫아버린 Claude 세션 안에 존재했기 때문이다. 코드는 작동했다. 하지만 '왜(why)'는 사라져 있었다.

문득 깨달았다. 코드를 작성하는 속도를 높여준 도구들이, 그 이후의 모든 과정인 리뷰, 디버깅, 온보딩, 유지보수에서는 나를 더 느리게 만들고 있다는 것을. 나는 코드를 10배 속도로 생성하고 있었지만, 나중에 그 대가를 0.5배의 속도로 치르고 있었다.

내가 시도했던 해결책들

나는 이 문제를 스스로 해결하려고 노력했다.

내 저장소(repo)에 CLAUDE.md 파일을 설정했다. 이는 모든 AI 세션에 로드되는 정적 컨텍스트(static context) 파일이다. 도움이 되긴 했다. 하지만 수동적이며, 코드베이스(codebase)가 진화하는 순간 바로 구식이 되고, 매 세션마다 비대해지기 시작하기 전 고작 몇 백 줄 정도에서 한계에 부딪힌다. 더 중요한 점은, 이것이 세션 수준(session-level)의 컨텍스트가 아닌 프로젝트 수준(project-level)의 컨텍스트를 포착한다는 것이다. 이것은 Claude에게 "우리는 상태 관리(state management)를 위해 Zustand를 사용한다"라고 말해줄 수는 있다. 하지만 "지난 화요일에 우리는 인증 흐름(auth flow)에 대한 세 가지 서로 다른 접근 방식을 논의했고, 이것이 우리가 이 방식을 선택한 이유이다"라고 말해줄 수는 없다.

수동으로 세션 노트(session notes)를 작성하는 것도 시도해 보았다. 그건 일주일 정도 지속되었다. 피곤할 때나, 혹은 컨텍스트가 가장 절실한 순간인 세션이 좌절 속에 끝났을 때 나는 노트를 건너뛰곤 했다.

커스텀 MCP 메모리 서버(custom MCP memory servers), SQLite 기반 솔루션, 개인용 스크립트 등을 조사해 보았다. 그중 일부는 인상적이었다. 하지만 그것들은 취약하고, 개인적이며, 근본적인 문제를 해결하지 못한다. 즉, 컨텍스트는 내 개인 시간에 따로 관리해야 하는 사이드 프로젝트가 아니라, 나의 개발 워크플로(development workflow) 안에 존재해야 한다는 문제 말이다.

내가 시도한 모든 임시방편(workaround)은 동일한 결함을 가지고 있었다. 그것들은 내가 매번 실수 없이 그 일을 수행할 수 있을 만큼 충분히 절제력이 있다는 것에 의존한다. 하지만 나는 그렇지 않다. 그 누구도 그렇지 않다. 그것이 바로 우리가 CI/CD, 린터(linters), 포매터(formatters)를 사용하는 이유다.

코드로서의 컨텍스트 (Context as Code)

모든 임시방편이 실패한 후, 나는 계속해서 같은 질문으로 돌아왔다. 왜 컨텍스트는 애초에 내가 수동으로 유지 관리해야 하는 것인가? 내 코드는 저장소(repo)에 있다. 내 테스트는 저장소에 있다. 내 CI 설정도 저장소에 있다. 그런데 왜 AI가 생성한 코드 뒤에 숨겨진 논리(reasoning)는 사라져 버리는 채팅창 안에 있는 것인가?

그때 나는 우리가 이미 '코드로서의 문서(Docs as Code)'를 통해 정확히 이 문제를 해결했다는 사실을 떠올렸다. 문서는 항상 별도의 시스템에 존재했기 때문에 구식이 되었다. 해결책은 간단했다. 문서를 저장소로 가져오고, Git과 마크다운(Markdown)을 사용하며, 이를 워크플로의 일부로 취급하는 것이었다. 그것이 성공했던 이유는 위키(wiki)를 업데이트하는 것을 사람들이 기억해야 한다는 점에 의존하는 것을 멈췄기 때문이다.

AI 코딩 (AI coding)은 동일한 격차의 새로운 버전을 만들어냈습니다. 하지만 뒤처지고 있는 것은 문서화 (documentation)가 아니라, 바로 _맥락 (context)_입니다. 코드가 왜 그렇게 작성되었는지에 대한 추론 (reasoning). 세션 동안 내려진 결정들. 고려되었으나 거부된 대안들. 이 모든 것이 매 커밋 (commit) 이후에 파괴되는 채팅창 안에 머물러 있습니다.

저는 이것을 **코드로서의 맥락 (Context as Code)**이라고 생각하기 시작했습니다. 코드와 함께 추론 과정을 캡처하고, 이를 버전 관리 (version control) 시스템에 저장하며, 누구나 읽을 수 있는 형식으로 작성하는 것입니다. 코드베이스가 왜 지금과 같은 모습인지에 대한 내구성 있는 기록입니다. 별도의 도구도, 위키 (wiki)도, 당신의 머릿속도 아닙니다. 당신의 저장소 (repo) 안에, 해당 커밋과 연결된 상태로 존재해야 합니다.

'코드로서의 문서화 (Docs as Code)'가 오래된 문서를 용납할 수 없게 만들었다면, '코드로서의 맥락 (Context as Code)'은 문서화되지 않은 AI 커밋을 그만큼 불완전하게 느껴지도록 만들어야 합니다.

코드로서의 맥락 (Context as Code) 실천 시작하기

아무것도 설치하지 않고도 다음 커밋에서 바로 시도해 볼 수 있습니다.

다음 AI 코딩 세션이 끝난 후, 저장소에 context/2026-05-22-stripe-webhook.md와 같은 파일을 생성하세요. 그리고 다음 세 가지 내용을 채워 넣으세요.

AI에게 요청한 것. 세션의 목표를 한두 문장으로 작성합니다. "구독 업그레이드를 처리하고 멱등성 (idempotency)을 다루는 Stripe 웹훅 (webhook) 핸들러를 구축할 것."

AI가 취한 접근 방식과 그 이유. AI가 도달한 패턴이나 솔루션, 그리고 그 이면의 추론입니다. "중복 결제를 방지하기 위해 이벤트 ID와 구독 기간을 모두 확인하는 2단계 검증 방식을 사용함."

거부한 것과 그 이유. 논의했으나 하지 않기로 결정한 접근 방식들입니다. 이 부분은 나중에 가장 고마워하게 될 부분입니다. "이벤트 ID만을 사용하는 더 간단한 멱등성 체크 방식을 거부함 — Claude가 동일한 결제 주기 전환 시점에 두 이벤트가 발생할 수 있는 경합 조건 (race condition)을 지적함."

그게 전부입니다. 파일 하나. 5분이면 충분합니다.

처음에는 그럴 만한 가치가 없다고 느껴질 것입니다. 하지만 3주 뒤, 당신은 스스로도 설명할 수 없는 파일을 디버깅하고 있을 것이고, 그때 컨텍스트 (context) 폴더를 확인하면 바로 눈앞에서 정확한 추론 (reasoning) 과정을 발견하게 될 것입니다. 2시간이 걸릴 디버깅 세션이 단 10분 만에 끝납니다.

수동 방식이 이해는 가지만 습관으로 정착되지 않는다면, 그것이 바로 우리가 Jolli Memory를 만든 이유입니다. 이 도구는 작업하는 동안 컨텍스트 (context)를 캡처하여 자체적인 Git 기반 프로젝트 저장소에 저장하며, 사용자의 코드 저장소 (repo)에는 절대 손을 대지 않습니다. Claude Code, Cursor, Codex CLI, Gemini CLI, 그리고 Copilot과 함께 작동합니다. 로컬 우선 (Local-first) 방식이며, 무료이고, 오픈 소스 (open source)입니다.

추론 (reasoning)은 살아남아야 한다

저는 바이브 코딩 (vibe coding)을 그만두지 않을 것입니다. 그것은 제가 무언가를 만드는 방식을 진정으로 바꾸어 놓았습니다. 하지만 터미널을 닫을 때마다 제 코드 뒤에 숨겨진 사고 과정이 사라지는 것을 더 이상 방치하지는 않을 것입니다.

다음 커밋 (commit) 때 시도해 보세요. 파일 하나. 5분이면 충분합니다. 그것이 당신의 월요일 아침을 어떻게 바꾸는지 확인해 보세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0