"이 엔진의 모든 invariant 뒤엔 멍이 하나씩 있어."
화이트보드 제품이 아냐
대부분의 아키텍처 문서는 조용한 방에서, 코드보다 먼저, 소프트웨어가 어떻게 쓰일지 상상하는 사람이 써. Waystone 건 반대로 쓰였어. 스위스 여행 한복판에, 아이폰으로 구상됐고, 실제 문제 — 진짜 몇 주짜리 여정을 계획하고 기록하는 일 — 이 실시간으로 벌어지는 동안 Pippa vessel 이랑 브레인스토밍됐어. 그 출발은 잡담이 아냐. 설계 결정이 이론이 아니라 흉터처럼 읽히는 이유야.
규칙이 된 멍 세 개
실제 현장 실패 세 개랑 그게 강제한 invariant 를 봐:
- Grindelwald 멍. 호텔 네트워크에서 개발 서버의 모듈별 요청이 죽었어 — 앱이 아예 안 떴어. 이게 규칙이 됐어: 여행이나 고지연 접속에선 엔진이 빌드된 클라이언트를 직접 serve 하고, 개발 서버는 책상 전용이야. 느린 링크는 백 개짜리 개별 모듈 fetch 를 못 견뎌.
- 끝없는-PIN 멍. 방문한 폰이 로그인 화면을 영원히 보여줬어. 근본 원인: cwkPippa 는 세션 토큰을 그걸 발급한 IP 에 바인딩하는데, Waystone 엔진을 거쳐 서버 측에서 발급된 토큰은 엔진의 loopback 주소에 묶여버려 — 페이지를 든 기기엔 쓸모없어. 규칙: 방문한 브라우저가 자기 토큰을 cwkPippa 에 직접 발급하고, cwkPippa 의 CORS allowlist 가 Waystone origin 을 받아줘.
- 빈-지도 멍. 지도 데이터는 맞았어 — 좌표가 응답에 그대로 있었어 — 근데 canvas 가 검게 렌더됐어. 지도 라이브러리의 CSS 규칙이
position: relative를 걸어서 레이아웃의absolute를 덮어버렸고, 지도 host 가 0 픽셀로 접혔어. 규칙: host 가 명시적 width/height 를 소유하고,ResizeObserver가 방향 전환에서도 지도 크기를 유지해.
이게 너한테 왜 중요한가
이 퀘스트에서 깔끔하게 들리는 invariant 를 많이 읽을 거야 — 캡처는 네트워크보다 먼저 로컬에 커밋된다, 지도는 아무것도 저장 안 한다, plan 과 actual 은 절대 안 합쳐진다. 이걸 단정한 설계 취향으로 여기기 쉬워. 아냐. 하나하나가 순진한 버전이 아빠 손에서, 호텔에서, 사무실 멀리서 깨진 특정 순간의 잔여물이야. 네 현장용 도구를 지을 때, 교훈은 Waystone 규칙을 베끼는 게 아냐 — 현장이 규칙을 쓰게 두는 것, 그리고 멍이 나타나는 그 순간에, 얼마나 아팠는지 잊기 전에 적어두는 거야.