"Pippa Go 대화는 승격을 기다리는 폰 초안이 아냐. 첫 숨부터 진짜 백엔드 대화야."
모바일 클라이언트를 만드는 두 가지 방식, 하나는 함정
모바일 대화가 어디 사는지를 두고 머릿속 그림이 두 개 있어. 어느 쪽을 고르냐가 전부를 결정하고.
- 초안 먼저, 업로드 나중 (함정). 폰이 로컬 대화를 갖고 있고, 백엔드로 내보내기 전까진 그게 '진짜' 야. 백엔드는 그냥 동기화 대상이고, 폰이 정한 걸 베껴 놓은 복사본이고.
- 태어날 때부터 canonical (Pippa Go). 대화가 첫 턴부터 어엿한 백엔드 대화야. 폰은 '진짜 그거' 를 가진 적이 없어. 백엔드가 이미 갖고 있는 대화를 대신 캡처하고 보여줄 뿐이지.
초안 먼저 모델은 자연스러워 보이는데 실은 천천히 굴러오는 재앙이야. 폰이 권위 있는 복사본을 쥐는 순간, 어긋날 수 있는 진실의 출처 둘이랑, 중간에 실패할 수 있는 승격 단계랑, 아무도 쓰기 싫어하는 병합 로직이 한꺼번에 생겨. 태어날 때부터 canonical 은 애초에 폰한테 권위를 안 줌으로써 그걸 전부 없애 버리고.
'태어날 때부터 canonical' 이 사주는 것
대화가 바로 canonical 이니까 백엔드 보장을 전부 공짜로 물려받아. 나중에 언젠가가 아니라 첫 턴부터.
- 완전한 컨텍스트 리플레이. 앞으로 어느 턴에서든 백엔드가 대화 전체를 다시 만들어낼 수 있어. 처음부터 갖고 있었으니까.
- 브랜치 의미. 다른 대화랑 똑같은 장치로 브랜치하고 돌아다닐 수 있어. 애초에 그 다른 대화랑 같은 물건이니까.
- 안 날아가는 ground truth. 대화가 첫 턴부터 백엔드의 append-only 로그에 살아. 폰에만 있어서 날아갈 수 있는 구간이 없고.
트랙 2 의 폰 로컬 outbox 는 이거랑 안 부딪혀. outbox 가 하는 일은 캡처야. 날아가는 중인 입력이 폰 쪽에서 잠깐 대기하는 자리. 대화 자체는 백엔드에서 canonical 이고. 저장소는 둘인데 하는 일이 달라. outbox 는 가는 길에 있는 질문을 지키고, canonical 로그는 도착한 대화를 갖는 거야.
이 모델이 답해 주는 질문
모바일 클라이언트를 볼 때 이렇게 물어봐. '지금 이 폰이 호수에 빠지면 대화는 어떻게 돼?' 초안 먼저 모델에선 아직 승격 안 된 게 그냥 사라져. 폰이 진실이었으니까. 태어날 때부터 canonical 이면, 백엔드에 닿은 턴은 전부 멀쩡하고 outbox 에 남은 질문은 전부 상태를 아는 pending 캡처야. 권위 있는 게 폰에만 있었던 적이 한 번도 없거든. 클라이언트가 뇌 되기를 거부하는 이유가 그 답 안에 다 들어 있어.