
Claude Code에 구현을 통째로 맡겼더니, 개인 개발의 병목이 '쓰는 것'에서 '결정하는 것'으로 변한 이야기
요약
Claude Code를 활용한 개인 앱 개발 과정에서 개발의 병목이 '코드 작성'에서 '의사결정'으로 변화하는 경험을 다룹니다. AI 에이전트의 기억력 한계와 맥락 부재 문제를 해결하기 위해 문서화 체계를 구축하고 온보딩 전략을 적용하는 방법을 소개합니다.
핵심 포인트
- 개발 병목이 코드 작성에서 사양 결정 및 리뷰로 이동함
- AI 에이전트의 세션 휘발성 및 맥락 부재 문제 해결 필요
- CLAUDE.md와 상세 설계서를 통한 AI 온보딩 체계 구축
- 정보의 중복을 방지하기 위한 엄격한 문서 역할 분담
서론
"Claude Code에 구현을 통째로 맡겼더니 2주 만에 앱이 완성되었다" —— 그렇게 말하면 듣기에는 좋지만, 정확하지 않습니다. 실제로 일어난 일은, 개발의 병목(Bottleneck)이 '코드를 쓰는 시간'에서 '결정하는 시간'으로 옮겨간 것입니다.
체중 감량 목표(10월 말까지 -8kg)를 위해 체중·식사·수분·근력 운동·일기를 기록하고 주간 리뷰 + AI 코칭으로 되돌아보는 로컬 퍼스트(Local-first) PWA인 「카라다 로그(からだログ)」를 개인 개발하고 있습니다. 요구사항 정의(Requirements Definition)를 쓰기 시작한 것이 7월 1일, 구현 시작이 7월 5일. 약 2주간의 실적은 다음과 같습니다.
- Issue 77건, PR 60개 (squash 머지 운용)
- 자동 테스트 370케이스
- 기록계 MVP부터 AI 코칭·Garmin 연동·혈압/습관 트래커까지 4단계 구현 완료
- 구현의 대부분은 Claude Code가 작성하고, 인간(나)은 거의 사양 결정과 리뷰만 수행
이 병목의 이동을 전제로 하면, 인간 측의 업무는 "결정한 것을 AI가 헤매지 않는 형태로 남기는 것"이 됩니다. 이 기사에서는 이를 위해 사용하고 있는 문서 구성과 운용 규칙을 실제 리포지토리(Repository)를 통해 소개합니다.
AI 에이전트 개발에서 실제로 발생하는 문제
Claude Code와 같은 에이전트에게 어느 정도 규모의 개발을 맡기면, 코딩 능력과는 별개의 문제에 부딪힙니다.
세션은 기억을 가지고 있지 않다. 오늘의 세션은 어제의 세션에서 나누었던 "동기화 대상은 기존 시트가 아니라 신규 시트로 하자"라는 대화를 알지 못합니다. 아무런 대책을 세우지 않으면, 새로운 세션은 과거의 결정을 아무렇지 않게 뒤집으며 모순되는 구현을 만들어냅니다.
'왜(Why)'가 사라진다. 코드에는 '무엇을 하고 있는가'만 남습니다. "그래프의 목표선이 왜 노란색이 아니라 회색인가" (디자인 가이드에서 노란색은 달성 연출 전용으로 정했기 때문)라는 이유를 모르는 AI는, 잘되라고 목표선을 눈에 띄는 노란색으로 "개선"해 버립니다.
암묵적인 불변 조건(Invariant)을 위반한다. "synced: true를 직접 설정해도 되는 것은 동기화 엔진뿐이다"와 같은 규칙은 타입(Type)에 나타나지 않으므로, grep으로 비슷한 코드를 발견한 AI가 악의 없이 위반합니다.
이 모든 것은 AI가 멍청해서 발생하는 것이 아니라, 인간 신입 멤버가 온보딩(Onboarding) 없이 참여했을 때 일어나는 일이 그대로 일어나고 있는 것뿐입니다. 따라서 대책도 마찬가지로, 온보딩 자료를 정비하는 것이 됩니다. 차이점은 AI는 몇 번이고 불평 없이 다시 읽어준다는 점입니다.
전체상: 문서의 역할 분담
리포지토리의 문서는 다음과 같이 나누어져 있습니다.
CLAUDE.md … AI의 안내도 (커맨드, 개발 플로우, 아키텍처의 요점, 금지 사항)
docs/
카라다 로그_요구사항 정의서.md … 무엇을 만드는가·왜 만드는가·무엇을 만들지 않는가
카라다 로그_화면 설계서.md … 화면 사양과 데이터 모델, 동기화 플로우
카라다 로그_디자인 가이드.md … 팔레트, 타이포그래피, 레이아웃 규칙
카라다 로그_AI 컨설팅 설계서.md … AI 코칭의 데이터 계약·프롬프트·프라이버시
카라다 로그_의사결정 로그.md … 결정된 논점의 '경위' 기록
카라다 로그_리뷰 체크리스트.md … 전체 리뷰의 기계적인 절차서
GitHub Issues … 남은 작업의 유일한 관리 장소 (백로그의 md 파일은 만들지 않음)
포인트는 정보의 위치를 역할에 따라 엄격하게 나누고 있다는 점입니다.
| 알고 싶은 것 | 보는 곳 |
|---|---|
| 현재의 사양 | 사양서 본문 (요구사항 정의서·화면 설계서) |
| ... | |
| 이 분리는 AI만을 위한 것이 아니라, 정보의 중복과 모순을 방지하기 위한 것이기도 합니다. 동일한 사실을 두 곳에 쓰면 반드시 한쪽이 낡게 되므로, "진실의 정보원(Source of Truth)은 무엇인가"를 각 문서의 서두에 명시하고 있습니다 (CLAUDE.md에도 "진실의 정보원은 이 사양서들이며, 이 파일이 아니다"라고 적혀 있습니다). |
메커니즘 1: CLAUDE.md에는 '지도'와 '지뢰'만 적는다
CLAUDE.md는 AI가 매 세션 가장 먼저 읽는 파일입니다. 여기에 사양의 상세 내용을 적고 싶어지지만, 그렇게 적으면 사양서와 이중 관리가 됩니다. 대신 적고 있는 것은 다음 세 가지 종류입니다.
1. 커맨드와 환경의 사실. npm run test 실행 방법, 그리고 "npm run lint는 package.json에 정의되어 있지만 ESLint는 실제로는 들어있지 않음 — 믿지 말 것"과 같이, 시도하면 시간을 낭비하게 되는 함정.
2. 타입(Type)만으로는 읽어낼 수 없는 아키텍처상의 선택. 예를 들어 이 앱에서는, 체중 기록은 날짜(YYYY-MM-DD)를 기본 키(Primary Key)로 하여 "1일 1건·마지막 데이터 우선(last-write-wins)" 방식을 put()만으로 성립시키고, 식사 기록은 UUID 키를 사용하여 같은 날 여러 건을 허용하고 있습니다. 이러한 비대칭성은 타입 정의만 봐서는 의도를 알 수 없기 때문에, 이유와 함께 CLAUDE.md에 적어두고 있습니다.
3. 금지 사항은 반드시 이유와 함께. 예:
getUnsyncedWeightRecords는 Dexie의 인덱스가 아니라 JS 측의 .filter()로 필터링함 — IndexedDB는 boolean을 인덱스 키로 사용할 수 없다는 점과, 이 정도 규모에서는 충분히 가볍기 때문임. 이를 인덱스화하여 "최적화"하지 말 것.
이유 없는 금지는 똑똑한 AI일수록 "오래된 제약일 것"이라고 판단하여 어겨버립니다(인간 신입 사원과 같습니다). "왜 안 되는지"까지 세트로 작성하면 거의 확실하게 지켜지게 되었습니다. public/_redirects를 추가하면 Cloudflare 배포가 무한 리다이렉트로 인해 실패한다거나, useLiveQuery는 "로딩 중"과 "undefined로 해결됨"을 구분할 수 없으므로 ?? null로 정규화한다거나 하는, 한 번 밟았던 지뢰는 밟을 때마다 여기에 추가하고 있습니다. CLAUDE.md는 작성하고 끝내는 것이 아니라, 사고가 날 때마다 키워나가는 운영 파일입니다.
메커니즘 2: 의사결정 로그 — "경위"를 사양서에서 분리하기
처음에는 요구사항 정의서 안에 "검토 경위"를 적었지만, 결정 사항이 늘어날수록 본문이 읽기 어려워지기 때문에, 경위만을 의사결정 로그로 분리했습니다. 형식은 심플하며, 테마별 섹션에 날짜를 붙여 추가해 나가기만 하면 됩니다.
2026-07-11: 멀티 유저화 방침 검토(#67) → 비용 대비 효과가 맞지 않는다고 판단하여 대응 불필요로 결정 후 클로즈. (...검토한 3가지 형태와 보류한 이유가 이어짐...)
이 방식이 효과적인 이유는, AI가 "하지 않기로 결정한 것"을 다시 제안하지 않게 만들기 때문입니다. 기능 추가를 요청하면 AI는 먼저 의사결정 로그를 확인하고, "클라우드 DB는 #67에서 보류되었으므로, 기존 시트 동기화 방식에 태우겠습니다"라는 전제부터 시작해 줍니다. 과거의 논의를 재연하는 일이 없어지는 것은 체감상 상당히 큰 시간 절약입니다.
주의할 점은, 로그는 어디까지나 경위의 기록이며, 현재 사양의 정답은 사양서 본문이라는 규칙을 깨뜨리지 않는 것입니다. "로그에 적었으니 사양서는 업데이트하지 않아도 된다"를 허용하면 진실의 원천(Source of Truth)이 두 개로 갈라지게 됩니다.
메커니즘 3: Issue 주도 + 사양서로의 다시 쓰기(Write-back)를 "필수"로 만들기
일일 개발 루프는 다음과 같습니다.
- 비자명한 작업은 착수 전에 Issue를 생성한다 (1인 개발이라도). Issue에는 근거가 된 사양서의 해당 장을 링크한다. - main을 최신화하고 브랜치를 생성하여 구현.
npm run test/npm run build로 검증, UI 변경은 Playwright로 스크린샷 확인. - 사양에 영향을 주는 변경은 해당 사양서 본문을 현재 사양에 맞게 수정한다 (필수). 보류했던 논점을 구현했다면, 논점 리스트와 의사결정 로그에도 경위를 남긴다. - PR 생성 전 리뷰 체크리스트 관점에서 자기 점검. - PR을 생성하고 (Closes #N), 사용자의 명시적인 지시에 따라 squash merge.
이 루프 자체를 CLAUDE.md의 "개발 플로우" 섹션에 적어두었기 때문에, AI는 지시하지 않아도 이 절차대로 움직입니다. 특히 3번의 다시 쓰기의 필수화가 사양서 주도 개발의 생명선입니다. 다시 쓰기를 게을리하면 사양서는 며칠 만에 "과거의 구상 메모"로 퇴화하고, AI가 그것을 사실로 읽는 사고가 발생하기 시작합니다. 반대로 다시 쓰기가 순환되는 한, 새로운 세션은 언제 시작하더라도 최신 사양에서 출발할 수 있습니다.
"순수한 버그 수정 및 리팩토링은 다시 쓰기 불필요. 단, 영향 여부는 매번 판단한다"라는 예외 조항도 명문화해 두었습니다. 전부 다 다시 쓰라고 하면 운영이 파탄 나기 때문에, 판단 기준과 함께 규칙화하는 것이 요령입니다.
메커니즘 4: 리뷰를 "체크리스트"로서 절차화하기
한 번 리포지토리 전체 리뷰를 수행했을 때, 그 관점을 일회성으로 소비하지 않고 docs/karada_log_리뷰_체크리스트.md에 절차화했습니다. 포인트는 판단이 적은 기계적인 절차로 떨어뜨리는 것입니다. 예를 들어 코드 불변 조건(Invariant) 체크는 grep 명령어와 합격 조건의 세트로 구성되어 있습니다.
| 체크 | 명령어 | 합격 조건 |
|---|---|---|
synced: true 직접 설정 | grep -rn "synced: true" src/ | 히트되는 항목은 동기화 엔진, 인입(Ingestion), 테스트뿐이어야 함 |
| 이모지 혼입 | grep -rnP "[이모지 범위]" src/ | 0건 (아이콘은 SVG 컴포넌트로만 구성) |
| accent 색상 오용 | grep -rn "FFC145" src/ | 「달성하는 순간의 연출」 용도로만 사용 |
| Worker의 로컬 TZ(타임존) 의존 | grep -n "getHours..." worker/ | 0건 (Worker는 UTC로 동작) |
여기까지 기계화해 두면, "전체 리뷰해줘"라는 한마디로 어떤 세션의 AI라도 동일한 품질의 점검을 재현할 수 있습니다. 리뷰 관점의 개인화(세션별 파편화)를 방지하는 문서라는 위치로, 이것 또한 사고가 발생할 때마다 항목을 추가하고 있습니다. 실제로, 인증되지 않은 API로부터 건강 데이터를 읽을 수 있다는 진짜 지적은 이 전체 리뷰 과정에서 나왔습니다.
2주간 해보며 느낀 점
효과를 본 점:
- 결정 사항의 재사용이 용이함. 유사한 기능(혈압, 둘레, 습관 트래커) 추가 시 "기존 패턴에 맞춰서"라는 한마디로 끝납니다. 패턴 자체가 문서화되어 있기 때문입니다.
- 세션을 넘나드는 재작업(rework)이 거의 사라짐. 과거의 결정과 모순되는 구현이 나오지 않습니다.
- 인간의 업무가 명확해짐. 내가 하는 일은 논점에 결론을 내는 것, 모크(Mock)나 실제 화면을 보고 판단하는 것, 머지(Merge) 승인입니다. 코드 리뷰는 하지만, 직접 코드를 쓰는 일은 거의 없습니다.
비용과 한계:
- 문서 유지에는 비용이 듭니다. 다시 기록하는 과정을 포함하면 체감상 작업 시간의 2~3할이 문서화에 쓰입니다.
- 그럼에도 차이는 발생합니다. 그래서 리뷰 체크리스트(3장의 정합성 체크)가 보험으로서 필요합니다.
- 명세서에 적혀 있지 않은 암묵적인 기대는 당연히 구현되지 않습니다. "적혀 있지 않은 것은 존재하지 않는다"라고 생각하며 작성해야 합니다.
이 비용은 일회성으로 쓰고 버릴 코드라면 명백히 과도합니다. 하지만 몇 주 이상 지속되는 프로젝트에서 세션(또는 사람)을 넘나들며 문맥을 이어가야 한다면, 충분히 본전을 뽑을 수 있다는 것이 현시점의 결론입니다.
요약
- AI 에이전트와의 개발에서 발생하는 문제는 온보딩(Onboarding)이 없는 신규 멤버에게 발생하는 문제와 같다. 대책 또한 온보딩 자료의 정비다.
- 정보는 역할에 따라 보관 장소를 나눈다: 현재의 사양 = 명세서, 경위 = 의사결정 로그, 남은 작업 = Issue, 다루는 법과 지뢰 = CLAUDE.md
- 금지 사항은 이유와 함께 작성한다. 이유 없는 금지는 AI에 의해 깨진다.
- 구현 후 명세서에 다시 기록하는 것을 필수 규칙으로 만든다. 이것이 무너지면 전부 무너진다.
- 리뷰 관점은 체크리스트로서 절차화하여, 어떤 세션에서도 재현 가능하게 만든다.
이 앱 자체(실측 TDEE의 역산, AI에게는 계산을 시키지 않고 언어화만 시키는 설계, Google Sheets를 개인용 DB로 사용하는 동기화 엔진)에 관한 이야기는 각각 별도의 글로 작성할 예정입니다.
이 앱을 애초에 왜 직접 만들었는지에 대한 경위는 note에 작성했습니다:
건강 관리 도구가 5개로 분산되어 있어서, AI와 2주 만에 자작 앱으로 통합한 이야기
코드와 명세서는 모두 GitHub에 공개되어 있습니다: https://github.com/yotti773/lifelog
Discussion

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