코드보다 먼저 — 아키텍처 설계
코딩을 시작하기 전에 반나절을 설계에 썼다.
결론부터 말하면, 그 반나절이 이후 모든 것을 결정했다. 그리고 그 반나절이 필요했던 이유는, 내가 비개발자기 때문이다. 그리고 설계를 시작하기도 전에 이미 한 번 막혔기 때문이다.
첫 번째 벽 — 기획 세션이 먼저 터졌다
몇 달 전 kimeunsoo.xyz를 만들 때 일이다. 신나서 Claude Code 세션을 계속 돌렸다. 금방 한도에 걸렸다. AI가 이전 맥락을 잃으면 코드가 조금씩 엉키기 시작했다. 비개발자는 그게 엉킨 건지도 바로 모른다. 그냥 계속 시키다가 나중에 보면 뭔가 이상한 상태가 되어 있다.
이번엔 Pepper 기획 단계에서 또 같은 일이 일어났다. Claude Pro $20짜리로 구조 잡다 보니 기획 세션부터 한도에 걸렸다. 본격 구현도 시작 안 했는데.
"이거 어떻게 해결하지?"
이것도 Claude, Gemini랑 같이 고민했다. 나온 해결책이 결국 문서 시스템이었다.
핵심은 이거다. 세션이 바뀌어도 AI가 맥락을 잃지 않게 만들어야 한다. 그러려면 맥락이 내 머릿속이 아니라 문서에 있어야 한다.
그리고 또 하나. 내 머릿속이 흔들리면 AI도 길을 잃는다.
개발자는 머릿속에 시스템 구조가 어느 정도 고정되어 있다. 나는 아니다. 이야기하다 보면 흔들린다. 어제 맞다고 생각한 설계가 오늘 바뀔 수 있다. AI는 내가 흔들리는 걸 잡아주지 않는다. 그냥 흔들린 채로 코드를 짜기 시작한다.
아키텍처 앵커가 필요했다. 내 머릿속이 흔들려도 문서가 잡아주는 구조. 그리고 개발 진행 하면서도 흔들리지 않는 Source of Truth.
3개의 문서 — 코드 한 줄 치기 전에 만든 것들
context.md — 시스템 전체의 단 하나의 진실이다. North Star, 설계 원칙, 아키텍처, STATE A/B/C 정의가 다 들어있다. 절대 원칙이 하나 있다. 코드를 수정하기 전에 반드시 이 문서를 먼저 업데이트한다. 새 세션을 시작할 때 이 문서 하나만 주면 AI가 전체 맥락을 복구한다. 이게 세션 한도 문제의 실질적인 해결책이었다.
schema.md — 처음엔 없었다. context.md를 만들다 보니 "데이터 구조도 명확하게 문서화해야겠다"는 걸 깨달았다. Family Vault에 어떤 데이터를 어떻게 담을지, 가족 단위로 데이터를 어떻게 분리할지 — 이걸 모르면 데이터베이스 세팅할 때 AI가 제멋대로 만든다. 나중에 고치는 게 훨씬 힘들다.
roadmap.md — 전체 구현을 극도로 잘게 쪼갠 실행 계획이다. 각 step 끝에 "성공 조건"을 명확히 정의했다. 이유는 단순하다. 나도 모르기 때문이다. 성공 조건이 없으면 됐는지 안 됐는지를 내가 판단하지 못한다. 그리고 AI에게 한 번에 한 step만 시킨다. 여러 step을 동시에 시키면 맥락이 오염된다.
세션이 끝날 때는 handover.md로 현재 상태를 요약하고 다음 진입 지점을 기록한다. 새 세션 시작할 때 context.md + handover.md만 주면 AI가 어디까지 했는지 안다. .gitignore로 AI 컨텍스트에서 불필요한 파일들을 제외해서 토큰 낭비도 줄였다.
당연한 것처럼 보이지만, 비개발자에게는 이걸 설계하는 것 자체가 하나의 도전이었다. 그것도 AI랑 같이 풀었다.
use case를 계속 던지면서 구조가 만들어졌다
문서 시스템을 잡은 다음, 본격적으로 설계를 시작했다. 이게 그 반나절의 대부분이었다.
설계는 추상적인 논의에서 시작하지 않았다. 구체적인 일상의 장면들을 AI에게 계속 던지면서 구조가 만들어졌다.
"한국에선 네이버로 예약해야 해. 페퍼는 내가 평소에 어느 미용실 가는지 알아야 하고."
"근데 내가 외국 여행 가기 전에 현지 레스토랑을 예약할 수도 있잖아? 현재 위치랑 예약 대상 지역이 다를 수 있는데, 이걸 받아줄 수 있는 구조야?"
"내 미용실이 바뀌면? '미용실 바꿨어, 이제 OO헤어야'라고 말하면 자동으로 업데이트되어야 해."
이 대화에서 나온 설계가 있다. 사용자의 현재 위치와 예약 대상 지역을 분리해서 독립적으로 판단하는 구조. "머리 예약해줘"(현재 한국 → 네이버)와 "런던 호텔 예약해줘"(현재 한국이어도 → 글로벌 검색)가 같은 구조에서 자연스럽게 처리된다. 그리고 선호하는 미용실 같은 정보는 Vault에 저장해두고, 다음 예약부터 자동으로 반영된다. "미용실 바꿨어" 한 마디로 업데이트된다.
"은수가 용돈 달라고 하면 토스 딥링크로 바로 연결되면 어때?"
"은수, 은제한테 to-do 클리어하면 포인트 주는 시스템은? 그 포인트가 쌓이면 '아빠랑 놀기' 같은 상품권을 살 수 있는 마켓플레이스를 만들면?"
이게 Action Ledger와 Family Reward System이 되었다. 단순한 리마인더 앱이 아니라 가족 내의 행동과 보상을 연결하는 구조. 나중에 다 구현할 수 있을지 모르지만, 데이터 구조는 처음부터 이걸 받을 수 있게 만들어야 했다.
"Family Vault에 문서뿐만 아니라 우리가 좋아했던 맛집, 레시피도 담아두고 — 그 위에서 페퍼가 활동하면?"
Vault의 범위가 여기서 확장됐다. 금융 자산이나 법적 문서를 넘어서 가족의 취향과 기억까지. 페퍼에게 "오늘 외식 어디 갈까요?"를 물으면 Vault에 쌓인 우리 가족의 맛집 기록을 기반으로 제안할 수 있다.
이 대화들이 설계를 만들었다. 내가 구조를 알아서 만든 게 아니라, use case를 던지고 *"이걸 받아줄 수 있는 구조야?"*를 계속 물으면서.
확장성이 핵심이었다
이 모든 use case를 지금 다 구현할 수는 없다. 그것도 처음부터 알고 있었다.
하지만 중요한 건 나중에 추가할 때 뒤집어엎지 않아도 되는 구조를 처음부터 만드는 것이었다. 설계하면서 계속 자문했다. "이게 나중에 커졌을 때도 버틸 수 있는 구조인가?"
구체적으로 고민한 시나리오들:
가족 4명이 쓴다. 권한 구조가 처음부터 있어야 한다. 내가 은수에게 할 수 있는 것과 은수가 나에게 할 수 있는 것이 다르다.
이메일 계정이 하나가 아닐 수 있다. 개인 계정도 여러개 있을 수 있다. 업무 계정까지 연결 할수 있을지는 모르겠지만, 둘다 사용할 수도 있다. 즉 한 사람이 여러 계정을 연동할 수 있어야 한다.
우리 가족만 쓰는 게 아닐 수 있다. 나중에 다른 가족도 쓸 수 있다면? 데이터 설계 첫 단계부터 가족 단위의 완전한 데이터 격리를 적용했다. 지금은 우리 가족만 있지만, 구조는 처음부터 여러 가족을 받을 수 있게.
지금 모든 use case를 알 수 없다. 그러니 구조만큼은 최대한 넓게 만들어야 했다. 그게 schema.md를 따로 만들게 된 이유이기도 하다.
반나절의 결과
설계를 끝냈을 때 손에 남은 건 세 개의 문서였다. context.md, schema.md, roadmap.md.
코드는 한 줄도 없었다. 그런데 이상하게 자신이 있었다. 뭘 만들어야 하는지 알고 있었고, 어떤 순서로 만들어야 하는지 알고 있었고, 됐는지 안 됐는지 확인하는 방법도 알고 있었다.
이제 한번 구현해 볼 차례다.